Esempio n. 1
0
    def test_ioctl_get_immutable(self):
        #
        # Test the `ioctl_get_immutable()` helper and make sure it works
        # as intended.
        #

        with open(f"{self.vartmpdir.name}/immutable", "x") as f:
            assert not linux.ioctl_get_immutable(f.fileno())
Esempio n. 2
0
    def can_modify_immutable(path: str = "/var/tmp") -> bool:
        """Check Immutable-Flag Capability

        This checks whether the calling process is allowed to toggle the
        `FS_IMMUTABLE_FL` file flag. This is limited to `CAP_LINUX_IMMUTABLE`
        in the initial user-namespace. Therefore, only highly privileged
        processes can do this.

        There is no reliable way to check whether we can do this. The only
        possible check is to see whether we can temporarily toggle the flag
        or not. Since this is highly dependent on the file-system that file
        is on, you can optionally pass in the path where to test this. Since
        shmem/tmpfs on linux does not support this, the default is `/var/tmp`.
        """

        with tempfile.TemporaryFile(dir=path) as f:
            # First try whether `FS_IOC_GETFLAGS` is actually implemented
            # for the filesystem we test on. If it is not, lets assume we
            # cannot modify the flag and make callers skip their tests.
            try:
                b = linux.ioctl_get_immutable(f.fileno())
            except OSError as e:
                if e.errno in [errno.EACCES, errno.ENOTTY, errno.EPERM]:
                    return False
                raise

            # Verify temporary files are not marked immutable by default.
            assert not b

            # Try toggling the immutable flag. Make sure we always reset it
            # so the cleanup code can actually drop the temporary object.
            try:
                linux.ioctl_toggle_immutable(f.fileno(), True)
                linux.ioctl_toggle_immutable(f.fileno(), False)
            except OSError as e:
                if e.errno in [errno.EACCES, errno.EPERM]:
                    return False
                raise

        return True
Esempio n. 3
0
    def test_ioctl_toggle_immutable(self):
        #
        # Test the `ioctl_toggle_immutable()` helper and make sure it works
        # as intended.
        #

        with open(f"{self.vartmpdir.name}/immutable", "x") as f:
            # Check the file is mutable by default and if we clear it again.
            assert not linux.ioctl_get_immutable(f.fileno())
            linux.ioctl_toggle_immutable(f.fileno(), False)
            assert not linux.ioctl_get_immutable(f.fileno())

            # Set immutable and check for it. Try again to verify with flag set.
            linux.ioctl_toggle_immutable(f.fileno(), True)
            assert linux.ioctl_get_immutable(f.fileno())
            linux.ioctl_toggle_immutable(f.fileno(), True)
            assert linux.ioctl_get_immutable(f.fileno())

            # Verify immutable files cannot be unlinked.
            with self.assertRaises(OSError):
                os.unlink(f"{self.vartmpdir.name}/immutable")

            # Check again that clearing the flag works.
            linux.ioctl_toggle_immutable(f.fileno(), False)
            assert not linux.ioctl_get_immutable(f.fileno())

            # This time, check that we actually set the same flag as `chattr`.
            subprocess.run(
                ["chattr", "+i", f"{self.vartmpdir.name}/immutable"],
                check=True)
            assert linux.ioctl_get_immutable(f.fileno())

            # Same for clearing it.
            subprocess.run(
                ["chattr", "-i", f"{self.vartmpdir.name}/immutable"],
                check=True)
            assert not linux.ioctl_get_immutable(f.fileno())

            # Verify we can unlink the file again, once the flag is cleared.
            os.unlink(f"{self.vartmpdir.name}/immutable")