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

Fix #725 and #729. /tmp/pip-build issues #734

Merged
merged 16 commits into from
Jan 26, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
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: 1 addition & 1 deletion docs/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ News
Next Release
============

Beta and final releases of 1.3 are planned for the end of 2012.
Beta and final releases of 1.3 are planned for Feb 2013.


.. include:: ../CHANGES.txt
Expand Down
29 changes: 28 additions & 1 deletion pip/locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import site
import os
import tempfile
import getpass
from pip.backwardcompat import get_python_lib
import pip.exceptions


def running_under_virtualenv():
Expand All @@ -25,6 +27,31 @@ def virtualenv_no_global():
if running_under_virtualenv() and os.path.isfile(no_global_file):
return True

def _get_build_prefix():
""" Returns a safe build_prefix """
path = os.path.join(tempfile.gettempdir(), 'pip-build-%s' % \
getpass.getuser())
if sys.platform == 'win32':
""" on windows(tested on 7) temp dirs are isolated """
return path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

help me out, why the quick return for windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.getuid() and other calls used later in the function do not work on windows.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

windows temp dirs are user isolated/protected anyway, atleast on some versions of windows.
on windows 7, you get something like this:

tempfile.gettempfir()
c:\users\me\appdata\local\temp

how about a comment mentioning that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. I don't use windows so I had no idea.

try:
os.mkdir(path)
except OSError:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this try/except ? why not just if os.path.isdir(path)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I am ensuring there isn't a TOCTOU[0] bug here. If you did a os.path.isdir(path) that would would be vulnerable. [0] http://en.wikipedia.org/wiki/Time_of_check_to_time_of_use

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, good, got it.

file_uid = None
try:
fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
file_uid = os.fstat(fd).st_uid
os.close(fd)
except OSError:
file_uid = None
if file_uid != os.getuid():
msg = "The temporary folder for building (%s) is not owned by your user!" \
% path
print (msg)
print("pip will not work until the temporary folder is " + \
"either deleted or owned by your user account.")
raise pip.exceptions.InstallationError(msg)
return path

if running_under_virtualenv():
build_prefix = os.path.join(sys.prefix, 'build')
Expand All @@ -33,7 +60,7 @@ def virtualenv_no_global():
# Use tempfile to create a temporary folder for build
# Note: we are NOT using mkdtemp so we can have a consistent build dir
# Note: using realpath due to tmp dirs on OSX being symlinks
build_prefix = os.path.realpath(os.path.join(tempfile.gettempdir(), 'pip-build'))
build_prefix = os.path.realpath(_get_build_prefix())

## FIXME: keep src in cwd for now (it is not a temporary folder)
try:
Expand Down
81 changes: 81 additions & 0 deletions tests/test_locations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""
locations.py tests

"""
import os
import sys
import shutil
import tempfile
import getpass
from mock import Mock
import pip

class TestLocations:
def setup(self):
self.tempdir = tempfile.mkdtemp()
self.st_uid = 9999
self.username = "example"
self.patch()

def tearDown(self):
self.revert_patch()
shutil.rmtree(self.tempdir, ignore_errors=True)

def patch(self):
""" first store and then patch python methods pythons """
self.tempfile_gettempdir = tempfile.gettempdir
self.old_os_fstat = os.fstat
self.old_os_getuid = os.getuid
self.old_getpass_getuser = getpass.getuser

# now patch
tempfile.gettempdir = lambda : self.tempdir
getpass.getuser = lambda : self.username
os.getuid = lambda : self.st_uid
os.fstat = lambda fd : self.get_mock_fstat(fd)

def revert_patch(self):
""" revert the patches to python methods """
tempfile.gettempdir = self.tempfile_gettempdir
getpass.getuser = self.old_getpass_getuser
os.getuid = self.old_os_getuid
os.fstat = self.old_os_fstat

def get_mock_fstat(self, fd):
""" returns a basic mock fstat call result.
Currently only the st_uid attribute has been set.
"""
result = Mock()
result.st_uid = self.st_uid
return result

def get_build_dir_location(self):
""" returns a string pointing to the
current build_prefix.
"""
return os.path.join(self.tempdir, 'pip-build-%s' % self.username)

def test_dir_created(self):
""" test that the build_prefix directory is generated when
_get_build_prefix is called.
"""

assert not os.path.exists(self.get_build_dir_location() ), \
"the build_prefix directory should not exist yet!"
from pip import locations
locations._get_build_prefix()
assert os.path.exists(self.get_build_dir_location() ), \
"the build_prefix directory should now exist!"

def test_error_raised_when_owned_by_another(self):
""" test calling _get_build_prefix when there is a temporary
directory owned by another user raises an InstallationError.
"""
from pip import locations
os.getuid = lambda : 1111
os.mkdir(self.get_build_dir_location() )
try:
locations._get_build_prefix()
raise AssertionError("An InstallationError should have been raised!")
except pip.exceptions.InstallationError:
pass