From acb672b6a179567632e032f547582f30fa2f4aa7 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Fri, 10 Jan 2014 10:40:51 +0000 Subject: Fixed a security issue with temporary files on the filesystem cache on UNIX. --- CHANGES | 5 +++++ jinja2/bccache.py | 29 +++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 6425de5..17e44ef 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,11 @@ Version 2.7.2 - Prefix loader was not forwarding the locals properly to inner loaders. This is now fixed. +- Security issue: Changed the default folder for the filesystem cache to be + user specific and read and write protected on UNIX systems. See `Debian bug + 734747`_ for more information. + +.. _Debian bug 734747: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=734747 Version 2.7.1 ------------- diff --git a/jinja2/bccache.py b/jinja2/bccache.py index f2f9db6..433a480 100644 --- a/jinja2/bccache.py +++ b/jinja2/bccache.py @@ -15,7 +15,9 @@ :license: BSD. """ from os import path, listdir +import os import sys +import errno import marshal import tempfile import fnmatch @@ -189,7 +191,9 @@ class FileSystemBytecodeCache(BytecodeCache): two arguments: The directory where the cache items are stored and a pattern string that is used to build the filename. - If no directory is specified the system temporary items folder is used. + If no directory is specified a default cache directory is selected. On + Windows the user's temp directory is used, on UNIX systems a directory + is created for the user in the system temp directory. The pattern can be used to have multiple separate caches operate on the same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` @@ -202,10 +206,31 @@ class FileSystemBytecodeCache(BytecodeCache): def __init__(self, directory=None, pattern='__jinja2_%s.cache'): if directory is None: - directory = tempfile.gettempdir() + directory = self._get_default_cache_dir() self.directory = directory self.pattern = pattern + def _get_default_cache_dir(self): + tmpdir = tempfile.gettempdir() + + # On windows the temporary directory is used specific unless + # explicitly forced otherwise. We can just use that. + if os.name == 'n': + return tmpdir + if not hasattr(os, 'getuid'): + raise RuntimeError('Cannot determine safe temp directory. You ' + 'need to explicitly provide one.') + + dirname = '_jinja2-cache-%d' % os.getuid() + actual_dir = os.path.join(tmpdir, dirname) + try: + os.mkdir(actual_dir, 0700) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + return actual_dir + def _get_cache_filename(self, bucket): return path.join(self.directory, self.pattern % bucket.key) -- cgit v1.2.1