GNU bug report logs - #45371
race condition in rm --preserve-root=all

Previous Next

Package: coreutils;

Reported by: Stephane Chazelas <stephane <at> chazelas.org>

Date: Tue, 22 Dec 2020 16:11:02 UTC

Severity: normal

To reply to this bug, email your comments to 45371 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-coreutils <at> gnu.org:
bug#45371; Package coreutils. (Tue, 22 Dec 2020 16:11:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Stephane Chazelas <stephane <at> chazelas.org>:
New bug report received and forwarded. Copy sent to bug-coreutils <at> gnu.org. (Tue, 22 Dec 2020 16:11:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Stephane Chazelas <stephane <at> chazelas.org>
To: bug-coreutils <at> gnu.org
Subject: 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




This bug report was last modified 3 years and 118 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.