@@ -260,13 +260,14 @@ no_error_logging(f::Function) =
260260 @test TEMP_CLEANUP_MAX[] == 3
261261 local t, f
262262 temps = String[]
263+ npending = 0
263264 # mktemp is normally cleaned up on completion
264265 mktemp (d) do path, _
265266 @test isfile (path)
266267 t = path
267268 end
268269 @test ! ispath (t)
269- @test length (TEMP_CLEANUP) == 0
270+ @test length (TEMP_CLEANUP) == npending
270271 @test TEMP_CLEANUP_MAX[] == 3
271272 # mktemp when cleanup is prevented
272273 no_error_logging () do
@@ -277,19 +278,26 @@ no_error_logging(f::Function) =
277278 t = path
278279 end
279280 end
281+ # Make deleteable again
280282 chmod (d, 0o700 )
281283 close (f)
282- @test isfile (t)
283- @test length (TEMP_CLEANUP) == 1
284- @test TEMP_CLEANUP_MAX[] == 3
285- push! (temps, t)
284+ if Libc. geteuid () == 0
285+ # Root can delete anything
286+ @test ! isfile (t)
287+ else
288+ npending += 1
289+ @test isfile (t)
290+ @test length (TEMP_CLEANUP) == npending
291+ @test TEMP_CLEANUP_MAX[] == 3
292+ push! (temps, t)
293+ end
286294 # mktempdir is normally cleaned up on completion
287295 mktempdir (d) do path
288296 @test isdir (path)
289297 t = path
290298 end
291299 @test ! ispath (t)
292- @test length (TEMP_CLEANUP) == 1
300+ @test length (TEMP_CLEANUP) == npending
293301 @test TEMP_CLEANUP_MAX[] == 3
294302 # mktempdir when cleanup is prevented
295303 no_error_logging () do
@@ -301,16 +309,24 @@ no_error_logging(f::Function) =
301309 t = path
302310 end
303311 end
312+ # Make deleteable again
304313 chmod (d, 0o700 )
305314 close (f)
306- @test isdir (t)
307- @test length (TEMP_CLEANUP) == 2
308- @test TEMP_CLEANUP_MAX[] == 3
309- push! (temps, t)
315+ if Libc. geteuid () == 0
316+ # Root can delete anything
317+ @test ! isdir (t)
318+ else
319+ @test isdir (t)
320+ npending += 1
321+ @test length (TEMP_CLEANUP) == npending
322+ @test TEMP_CLEANUP_MAX[] == 3
323+ push! (temps, t)
324+ end
310325 # make one more temp file
311326 t = mktemp ()[1 ]
327+ npending += 1
312328 @test isfile (t)
313- @test length (TEMP_CLEANUP) == 3
329+ @test length (TEMP_CLEANUP) == npending
314330 @test TEMP_CLEANUP_MAX[] == 3
315331 # nothing has been deleted yet
316332 for t in temps
@@ -319,8 +335,9 @@ no_error_logging(f::Function) =
319335 # another temp file triggers purge
320336 t = mktempdir ()
321337 @test isdir (t)
322- @test length (TEMP_CLEANUP) == 2
323- @test TEMP_CLEANUP_MAX[] == 4
338+ npending = 2
339+ @test length (TEMP_CLEANUP) == npending
340+ @test TEMP_CLEANUP_MAX[] == (Libc. geteuid () == 0 ? 3 : 4 )
324341 # now all the temps are gone
325342 for t in temps
326343 @test ! ispath (t)
@@ -420,6 +437,9 @@ function test_stat_error(stat::Function, pth)
420437 if stat === lstat && ! (pth isa AbstractString)
421438 return # no lstat for fd handles
422439 end
440+ if Libc. geteuid () == 0
441+ return # root bypasses permission checks
442+ end
423443 ex = try ; stat (pth); false ; catch ex; ex; end :: Base.IOError
424444 @test ex. code == (pth isa AbstractString ? Base. UV_EACCES : Base. UV_EBADF)
425445 pth isa AbstractString || (pth = Base. INVALID_OS_HANDLE)
@@ -550,16 +570,23 @@ function multiple_uv_errors(pfx::AbstractString, codes::AbstractVector{<:Integer
550570 return [Base. _UVError (pfx, code) for code in codes]
551571end
552572
573+ read_linux_id_map_max (file) = parse (Int, split (strip (read (file, String)), " " , keepempty = false )[end ]) % Cint
553574if ! Sys. iswindows ()
554575 # chown will give an error if the user does not have permissions to change files
555576 uid = Libc. geteuid ()
556577 @test stat (file). uid == uid
557578 @test uid == Libc. getuid ()
579+ maxuid = maxgid = - 1
580+ # Containers may have restricted uid/gid ranges
581+ if Sys. islinux () && isfile (" /proc/self/uid_map" )
582+ maxuid = read_linux_id_map_max (" /proc/self/uid_map" )
583+ maxgid = read_linux_id_map_max (" /proc/self/gid_map" )
584+ end
558585 if uid == 0 # root user
559- chown (file, - 2 , - 1 ) # Change the file owner to nobody
560- @test stat (file). uid != 0
561- chown (file, 0 , - 2 ) # Change the file group to nogroup (and owner back to root)
562- @test stat (file). gid != 0
586+ chown (file, maxuid - 1 , - 1 ) # Change the file owner to nobody
587+ @test maxuid == 1 || stat (file). uid != 0
588+ chown (file, 0 , maxgid - 1 ) # Change the file group to nogroup (and owner back to root)
589+ @test maxgid == 1 || stat (file). gid != 0
563590 @test stat (file). uid == 0
564591 @test chown (file, - 1 , 0 ) == file
565592 @test stat (file). gid == 0
@@ -1864,8 +1891,10 @@ if !Sys.iswindows()
18641891 @test ! isdir (joinpath (d, " empty_outer" ))
18651892
18661893 # But a non-empty directory is not
1867- @test_throws Base. IOError rm (joinpath (d, " nonempty" ); recursive= true )
1868- chmod (joinpath (d, " nonempty" ), 0o777 )
1894+ if Libc. geteuid () != 0 # root can override permissions
1895+ @test_throws Base. IOError rm (joinpath (d, " nonempty" ); recursive= true )
1896+ chmod (joinpath (d, " nonempty" ), 0o777 )
1897+ end
18691898 rm (joinpath (d, " nonempty" ); recursive= true , force= true )
18701899 @test ! isdir (joinpath (d, " nonempty" ))
18711900 end
@@ -2032,10 +2061,10 @@ end
20322061 chmod (fpath, 0o444 )
20332062 @test ! Sys. isexecutable (fpath)
20342063 @test Sys. isreadable (fpath)
2035- @test ! Sys. iswritable (fpath)
2064+ @test ! Sys. iswritable (fpath) skip = Libc . getuid () == 0
20362065 chmod (fpath, 0o244 )
20372066 @test ! Sys. isexecutable (fpath)
2038- @test ! Sys. isreadable (fpath) skip= Sys. iswindows ()
2067+ @test ! Sys. isreadable (fpath) skip= ( Sys. iswindows () || Libc . getuid () == 0 )
20392068 @test Sys. iswritable (fpath) skip= Sys. iswindows ()
20402069
20412070 # Ensure that, on Windows, where inheritance is default,
0 commit comments