Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean locale identifiers before loading from file #782

Merged
merged 2 commits into from
Apr 28, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions babel/localedata.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def exists(name):
"""
if not name or not isinstance(name, string_types):
return False
name = os.path.basename(name)
if name in _cache:
return True
file_found = os.path.exists(os.path.join(_dirname, '%s.dat' % name))
Expand Down Expand Up @@ -102,6 +103,7 @@ def load(name, merge_inherited=True):
:raise `IOError`: if no locale data file is found for the given locale
identifer, or one of the locales it inherits from
"""
name = os.path.basename(name)
_cache_lock.acquire()
try:
data = _cache.get(name)
Expand Down
30 changes: 29 additions & 1 deletion tests/test_localedata.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://babel.edgewall.org/log/.

import os
import pickle
import sys
import tempfile
import unittest
import random
from operator import methodcaller

from babel import localedata
import pytest

from babel import localedata, Locale, UnknownLocaleError


class MergeResolveTestCase(unittest.TestCase):
Expand Down Expand Up @@ -131,3 +137,25 @@ def listdir_spy(*args):
localedata.locale_identifiers.cache = None
assert localedata.locale_identifiers()
assert len(listdir_calls) == 2


def test_locale_name_cleanup():
"""
Test that locale identifiers are cleaned up to avoid directory traversal.
"""
no_exist_name = os.path.join(tempfile.gettempdir(), "babel%d.dat" % random.randint(1, 99999))
with open(no_exist_name, "wb") as f:
pickle.dump({}, f)

try:
name = os.path.splitext(os.path.relpath(no_exist_name, localedata._dirname))[0]
except ValueError:
if sys.platform == "win32":
pytest.skip("unable to form relpath")
raise

assert not localedata.exists(name)
with pytest.raises(IOError):
localedata.load(name)
with pytest.raises(UnknownLocaleError):
Locale(name)