คำตอบคือคุณทำไม่ได้เว้นแต่ระบบไฟล์ของคุณจะมีจุดบกพร่อง นี่คือเหตุผล:
มีการเรียกระบบสำหรับการเปลี่ยนชื่อไฟล์ของคุณที่กำหนดไว้ในfs/namei.c
ชื่อrenameat
:
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
int, newdfd, const char __user *, newname)
เมื่อมีการเรียกใช้ระบบจะทำการค้นหาพา ธ ( do_path_lookup
) บนชื่อ ติดตามสิ่งนี้ต่อไปและเราจะlink_path_walk
ได้สิ่งนี้:
static int link_path_walk(const char *name, struct nameidata *nd)
{
struct path next;
int err;
unsigned int lookup_flags = nd->flags;
while (*name=='/')
name++;
if (!*name)
return 0;
...
รหัสนี้ใช้กับระบบไฟล์ใด ๆ นี่หมายความว่าอย่างไร หมายความว่าหากคุณพยายามส่งผ่านพารามิเตอร์ที่มี'/'
อักขระจริงเป็นชื่อของไฟล์โดยใช้วิธีการดั้งเดิมมันจะไม่ทำตามที่คุณต้องการ ไม่มีทางหนีพ้นตัวละคร หากระบบไฟล์ "รองรับ" สิ่งนี้อาจเป็นเพราะ:
- ใช้อักขระ Unicode หรือสิ่งที่ดูเหมือนเครื่องหมายทับ แต่ไม่ใช่
- พวกเขามีจุดบกพร่อง
นอกจากนี้ถ้าคุณไม่ไปในและแก้ไขไบต์เพื่อเพิ่มตัวอักษรทับลงไปในชื่อไฟล์สิ่งเลวร้ายที่จะเกิดขึ้น นั่นเป็นเพราะคุณไม่สามารถอ้างถึงไฟล์นี้ด้วยชื่อ :( ตั้งแต่เมื่อใดก็ตามที่คุณทำ Linux จะถือว่าคุณกำลังอ้างถึงไดเร็กทอรีที่ไม่มีอยู่การใช้เทคนิค 'rm *' จะไม่ได้ผลเช่นกันเนื่องจาก bash เพียงแค่ขยายไปยังชื่อไฟล์ แม้rm -rf
จะใช้ไม่ได้เนื่องจากสเตรทซ์เรียบง่ายเผยให้เห็นว่าสิ่งต่าง ๆ ดำเนินไปอย่างไรภายใต้ประทุน (สั้นลง):
$ ls testdir
myfile2 out
$ strace -vf rm -rf testdir
...
unlinkat(3, "myfile2", 0) = 0
unlinkat(3, "out", 0) = 0
fcntl(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(3) = 0
unlinkat(AT_FDCWD, "testdir", AT_REMOVEDIR) = 0
...
โปรดสังเกตว่าการเรียกเหล่านี้ไปunlinkat
จะล้มเหลวเนื่องจากต้องอ้างถึงไฟล์ตามชื่อ