From 64e5ef1f17cd18cb8ca24f4e7107dfd28c18b378 Mon Sep 17 00:00:00 2001 From: Yuri Konotopov Date: Wed, 14 Sep 2022 16:24:43 +0400 Subject: Fixed #29027 -- Fixed file_move_safe() crash when moving files with SELinux. Thanks Florian Apolloner for the review. --- tests/files/tests.py | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'tests/files') diff --git a/tests/files/tests.py b/tests/files/tests.py index 9777d09e1c..b3478d2732 100644 --- a/tests/files/tests.py +++ b/tests/files/tests.py @@ -419,35 +419,61 @@ class FileMoveSafeTests(unittest.TestCase): os.close(handle_a) os.close(handle_b) - def test_file_move_copystat_cifs(self): + def test_file_move_permissionerror(self): """ - file_move_safe() ignores a copystat() EPERM PermissionError. This - happens when the destination filesystem is CIFS, for example. + file_move_safe() ignores PermissionError thrown by copystat() and + copymode(). + For example, PermissionError can be raised when the destination + filesystem is CIFS, or when relabel is disabled by SELinux across + filesystems. """ - copystat_EACCES_error = PermissionError(errno.EACCES, "msg") - copystat_EPERM_error = PermissionError(errno.EPERM, "msg") + permission_error = PermissionError(errno.EPERM, "msg") + os_error = OSError("msg") handle_a, self.file_a = tempfile.mkstemp() handle_b, self.file_b = tempfile.mkstemp() + handle_c, self.file_c = tempfile.mkstemp() try: # This exception is required to reach the copystat() call in # file_safe_move(). with mock.patch("django.core.files.move.os.rename", side_effect=OSError()): - # An error besides EPERM isn't ignored. + # An error besides PermissionError isn't ignored. with mock.patch( - "django.core.files.move.copystat", side_effect=copystat_EACCES_error + "django.core.files.move.copystat", side_effect=os_error ): - with self.assertRaises(PermissionError): + with self.assertRaises(OSError): file_move_safe(self.file_a, self.file_b, allow_overwrite=True) - # EPERM is ignored. + # When copystat() throws PermissionError, copymode() error besides + # PermissionError isn't ignored. with mock.patch( - "django.core.files.move.copystat", side_effect=copystat_EPERM_error + "django.core.files.move.copystat", side_effect=permission_error + ): + with mock.patch( + "django.core.files.move.copymode", side_effect=os_error + ): + with self.assertRaises(OSError): + file_move_safe( + self.file_a, self.file_b, allow_overwrite=True + ) + # PermissionError raised by copystat() is ignored. + with mock.patch( + "django.core.files.move.copystat", side_effect=permission_error ): self.assertIsNone( file_move_safe(self.file_a, self.file_b, allow_overwrite=True) ) + # PermissionError raised by copymode() is ignored too. + with mock.patch( + "django.core.files.move.copymode", side_effect=permission_error + ): + self.assertIsNone( + file_move_safe( + self.file_c, self.file_b, allow_overwrite=True + ) + ) finally: os.close(handle_a) os.close(handle_b) + os.close(handle_c) class SpooledTempTests(unittest.TestCase): -- cgit v1.2.1