bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#45371: race condition in rm --preserve-root=all


From: Stephane Chazelas
Subject: bug#45371: race condition in rm --preserve-root=all
Date: Tue, 22 Dec 2020 16:10:18 +0000

Hello,

[reproduced with rm 8.30 and current git head on ubuntu 20.04 amd64]

Whilst trying to answer
https://unix.stackexchange.com/questions/505317/using-rm-one-file-system-to-only-delete-files-on-the-local-filesystem

I noticed that "rm -rf --preserve-root=all some-dir" was not race-free.
"some-dir", as the root of a filesystem could still be removed recursively if
the filesystem is mounted after "rm" has checked that "some-dir" was not a
mountpoint but before "rm" opens that directory.

That can be reproduced with gdb:

$ mkdir -p 1 2/dir
$ gdb --quiet --args rm -rf --preserve-root=all --one-file-system 1
Reading symbols from rm...
(gdb) break __fxstatat
Breakpoint 1 at 0x25e0
(gdb) break __lxstat
Breakpoint 2 at 0x2570
(gdb) break unlinkat
Breakpoint 3 at 0x24d0
(gdb) r
Starting program: /home/chazelas/install/cvs/coreutils/INSTALL.d/bin/rm -rf 
--preserve-root=all --one-file-system 1

Breakpoint 2, __GI___lxstat (vers=1, name=0x55555556350c "/", 
buf=0x7fffffffd820) at ../sysdeps/unix/sysv/linux/wordsize-64/lxstat.c:33
33      ../sysdeps/unix/sysv/linux/wordsize-64/lxstat.c: No such file or 
directory.
(gdb) c
Continuing.

Breakpoint 1, __GI___fxstatat (vers=1, fd=-100, file=0x5555555705b0 "1", 
st=0x555555570520, flag=256) at 
../sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c:36
36      ../sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c: No such file or 
directory.
(gdb) c
Continuing.

Breakpoint 2, __GI___lxstat (vers=1, name=0x555555570700 "1/..", 
buf=0x7fffffffd7b0) at ../sysdeps/unix/sysv/linux/wordsize-64/lxstat.c:33
33      ../sysdeps/unix/sysv/linux/wordsize-64/lxstat.c: No such file or 
directory.
(gdb) fin
Run till exit from #0  __GI___lxstat (vers=1, name=0x555555570700 "1/..", 
buf=0x7fffffffd7b0) at ../sysdeps/unix/sysv/linux/wordsize-64/lxstat.c:33
0x000055555555839e in rm_fts (fts=0x55555556f200, ent=0x5555555704b0, 
x=0x7fffffffd900) at src/remove.c:473
473                   if (!parent || lstat (parent, &statbuf))
Value returned is $1 = 0
(gdb) !bindfs --no-allow-other 2 1
(gdb) !ls 1
dir
(gdb) c
Continuing.

Breakpoint 1, __GI___fxstatat (vers=1, fd=4, file=0x5555555706c0 "dir", 
st=0x555555570630, flag=256) at 
../sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c:36
36      ../sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c: No such file or 
directory.
(gdb) c
Continuing.

Breakpoint 3, unlinkat () at ../sysdeps/unix/syscall-template.S:78
78      ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) bt
#0  unlinkat () at ../sysdeps/unix/syscall-template.S:78
#1  0x0000555555557ddc in excise (fts=0x55555556f200, ent=0x5555555705c0, 
x=0x7fffffffd900, is_dir=true) at src/remove.c:370
#2  0x0000555555558547 in rm_fts (fts=0x55555556f200, ent=0x5555555705c0, 
x=0x7fffffffd900) at src/remove.c:508
#3  0x000055555555892d in rm (file=0x7fffffffda58, x=0x7fffffffd900) at 
src/remove.c:608
#4  0x000055555555749d in main (argc=5, argv=0x7fffffffda38) at src/rm.c:370
(gdb)


bindfs is a fuse-based file system to mount one directory over
another. 2 is mounted over 1 after rm has compared the result of
stat("1") and stat("1/.."), and we see unlink("1/dir") being
done.

It seems to me that race window could be closed if "." and ".."
were compared after the directory is opened.

-- 
Stephane





reply via email to

[Prev in Thread] Current Thread [Next in Thread]