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

pyfakefs seemingly ignores file permissions on write() #489

Closed
mcallaghan-bsm opened this issue Jun 18, 2019 · 3 comments
Closed

pyfakefs seemingly ignores file permissions on write() #489

mcallaghan-bsm opened this issue Jun 18, 2019 · 3 comments

Comments

@mcallaghan-bsm
Copy link

Describe the bug
We have come across this seemingly impossible scenario, where despite creating a file in pyfakefs, with completely removed permissions (effectively chmod 000), it is STILL allowed to write and read from it.

How To Reproduce
Here follows an example suite of tests:

class TestCaseExample(TestCase):


    def setUp(self):
        self.setUpPyfakefs()

    def test_create_file(self):
        file_path = 'file_foo.txt'

        self.assertFalse(os.path.exists(file_path))
        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))

    def test_default_file_perms(self):
        file_path = 'file_bar.txt'

        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))

        default_mask = 0o666
        initial_mask = stat.S_IMODE(os.lstat(file_path).st_mode)
        assert initial_mask == 0o666

    def test_impossible_write_capability(self):
        file_path = 'file_bat.txt'

        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))

        default_mask = 0o666
        initial_mask = stat.S_IMODE(os.lstat(file_path).st_mode)
        assert initial_mask == default_mask

        no_write_mask = 0o000
        os.chmod(file_path, no_write_mask)
        new_mask = stat.S_IMODE(os.lstat(file_path).st_mode)
        assert new_mask == no_write_mask

        # HERE ON SHOULD FAIL, but it does not
        # previously we set (and asserted) that the file mask is now `000`

        with open(file_path, 'w') as f:
            f.write('This should NOT be possible\n')

        with open(file_path) as f:
            print(f.read())

We EXPECT test_create_file and test_default_file_perms to PASS, and test_impossible_write_capability to FAIL. The failure is because in that last test we change the permissions to chmod 000, yet, these commands do not throw.

Run it like so:

(app) root@dbac90fda4f0:/app# python3 -m pytest tests/ut/pyfakefs/test_perms.py 
Test session starts (platform: linux, Python 3.7.3, pytest 4.6.3, pytest-sugar 0.9.2)
cachedir: .pytest_cache
rootdir: /app, inifile: pytest.ini
plugins: cov-2.7.1, sugar-0.9.2, pyfakefs-3.5.8, mock-1.10.4
collecting ... 
 tests/ut/pyfakefs/test_perms.py::TestCaseExample.test_create_file ✓                                                                                                                                 33% ███▍      
 tests/ut/pyfakefs/test_perms.py::TestCaseExample.test_default_file_perms ✓                                                                                                                          67% ██████▋   
 tests/ut/pyfakefs/test_perms.py::TestCaseExample.test_impossible_write_capability ✓                                                                                                                100% ██████████Coverage.py warning: No data was collected. (no-data-collected)

(snip coverages)

Results (0.89s):
       3 passed

Your enviroment

Note that we are in a docker, inside of python venv (via pipenv).

(app) root@dbac90fda4f0:/app# which python3
/root/.local/share/virtualenvs/app-4PlAip0Q/bin/python3
(app) root@dbac90fda4f0:/app# pipenv --version
pipenv, version 2018.11.26
(app) root@dbac90fda4f0:/app# python -c "import platform; print(platform.platform())"
Linux-4.15.0-51-generic-x86_64-with-debian-9.9
(app) root@dbac90fda4f0:/app# python -c "import sys; print('Python', sys.version)"
Python 3.7.3 (default, May  8 2019, 05:31:59) 
[GCC 6.3.0 20170516]
(app) root@dbac90fda4f0:/app# python -c "from pyfakefs.fake_filesystem import __version__; print('pyfakefs', __version__)"
pyfakefs 3.5.8
@mrbean-bremen
Copy link
Member

You are running as root, in this case pyfakefs also assumes root rights. It should work correctly if you run the code as non-root user, or change the user rights in your setup by calling set_uid on the fake filesystem. In master, there is also a convenience argument allow_root_user in setup that can be set to False.

@mcallaghan-bsm
Copy link
Author

mcallaghan-bsm commented Jun 19, 2019

Fantastic point @mrbean-bremen ! That is exactly it; apologies we did not notice this factor which is a clear explanation. We'll make the necessary adjustments. No issue/bug here then. (closing)

Here's an example (for future users landing here);

import os
import stat

#from pyfakefs.fake_filesystem_unittest import TestCase
import pyfakefs
import pytest


class TestCaseExample(pyfakefs.fake_filesystem_unittest.TestCase):
    

    def setUp(self):
        self.setUpPyfakefs()

    def test_create_file(self):
        file_path = 'file_foo.txt'

        self.assertFalse(os.path.exists(file_path))
        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))

    def test_default_file_perms(self):
        file_path = 'file_bar.txt'

        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))

        default_mask = 0o666
        initial_mask = stat.S_IMODE(os.lstat(file_path).st_mode)
        assert initial_mask == 0o666

    def test_impossible_write_capability(self):
        file_path = 'file_bat.txt'

        # Change the filesystem UID access to non-root
        # (HACK use www-data UID 33)
        pyfakefs.fake_filesystem.set_uid(33)

        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))

        default_mask = 0o666
        initial_mask = stat.S_IMODE(os.lstat(file_path).st_mode)
        assert initial_mask == default_mask

        no_write_mask = 0o000
        os.chmod(file_path, no_write_mask)
        new_mask = stat.S_IMODE(os.lstat(file_path).st_mode)
        assert new_mask == no_write_mask

        with pytest.raises(PermissionError) as e_info:
            with open(file_path, 'w') as f:
                f.write('This should NOT be possible\n')

        with pytest.raises(PermissionError) as e_info:
            with open(file_path) as f:
                # user should not be allowed to READ, expect PermissionError
                print(f.read())
(app) root@e2574646d5d0:/app# python3 -m pytest tests/ut/pyfakefs/test_perms.py
Test session starts (platform: linux, Python 3.7.3, pytest 4.6.3, pytest-sugar 0.9.2)
cachedir: .pytest_cache
rootdir: /app, inifile: pytest.ini
plugins: cov-2.7.1, sugar-0.9.2, pyfakefs-3.5.8, mock-1.10.4
collecting ... 
 tests/ut/pyfakefs/test_perms.py::TestCaseExample.test_create_file ✓                                                                                                                                 33% ███▍      
 tests/ut/pyfakefs/test_perms.py::TestCaseExample.test_default_file_perms ✓                                                                                                                          67% ██████▋   
 tests/ut/pyfakefs/test_perms.py::TestCaseExample.test_impossible_write_capability ✓                                                                                                                100% ██████████Coverage.py warning: No data was collected. (no-data-collected)

(snip coverage)

Results (0.94s):
       3 passed

@mrbean-bremen
Copy link
Member

Good point about future users - maybe we'll add this to the troubleshooting guide! With docker, this will probably happen more often now...

tchaikov added a commit to tchaikov/ceph that referenced this issue Oct 10, 2022
as we will be create/access directories which are only accessible by
root with pyfakefs, and pyfake respects the uid of current effective
user, so if we run the test using non-root user, these tests would fail
after the fix for pytest-dev/pyfakefs#489
is addressed in the pyfakefs we are using.

in this change, we will run the test on behalf of root, so we can
create and access the directories as we did before.

Signed-off-by: Kefu Chai <tchaikov@gmail.com>
tchaikov added a commit to tchaikov/ceph that referenced this issue Oct 10, 2022
as we will be create/access directories which are only accessible by
root with pyfakefs, and pyfake respects the uid of current effective
user, so if we run the test using non-root user, these tests would fail
after the fix for pytest-dev/pyfakefs#489
is addressed in the pyfakefs we are using.

in this change, we will run the test on behalf of root, so we can
create and access the directories as we did before.

Signed-off-by: Kefu Chai <tchaikov@gmail.com>
nizamial09 pushed a commit to rhcs-dashboard/ceph that referenced this issue Oct 11, 2022
as we will be create/access directories which are only accessible by
root with pyfakefs, and pyfake respects the uid of current effective
user, so if we run the test using non-root user, these tests would fail
after the fix for pytest-dev/pyfakefs#489
is addressed in the pyfakefs we are using.

in this change, we will run the test on behalf of root, so we can
create and access the directories as we did before.

Signed-off-by: Kefu Chai <tchaikov@gmail.com>
(cherry picked from commit ed19416)

 Conflicts:
	src/cephadm/tests/fixtures.py
  - Replace _cephadm with cd
adk3798 pushed a commit to adk3798/ceph that referenced this issue Oct 12, 2022
as we will be create/access directories which are only accessible by
root with pyfakefs, and pyfake respects the uid of current effective
user, so if we run the test using non-root user, these tests would fail
after the fix for pytest-dev/pyfakefs#489
is addressed in the pyfakefs we are using.

in this change, we will run the test on behalf of root, so we can
create and access the directories as we did before.

Signed-off-by: Kefu Chai <tchaikov@gmail.com>
(cherry picked from commit ed19416)

Conflicts:
	src/cephadm/tests/fixtures.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants