rm: Use basenames to protect against . and ..

POSIX mandates that the protection should care about the basename,
and we cannot use basename because it can modify the input string
and it would make harder later operations. Also, it would put a limit
in the length of the name of the paths and POSIX forbids limitations
about that regard in rm(1).
This commit is contained in:
Roberto E. Vargas Caballero 2025-04-25 12:37:10 +02:00
parent d4dfd42d35
commit b27871013b

44
rm.c
View File

@ -11,9 +11,44 @@ usage(void)
eprintf("usage: %s [-f] [-iRr] file ...\n", argv0);
}
static int
forbidden(char *path, struct stat *root)
{
char *s, *t;
size_t n;
struct stat st;
static int w1, w2;
n = strlen(path);
for (t = path + n; t > path && t[-1] == '/'; --t)
;
for (s = t; s > path && s[-1] != '/'; --s)
;
n = t - s;
if (n == 1 && *s == '.' || n == 2 && s[0] == '.' && s[1] == '.') {
if (!w1)
weprintf("\".\" and \"..\" may not be removed\n");
w1 = 1;
return 1;
}
if (stat(path, &st) < 0)
eprintf("stat argument '%s':", path);
if (st.st_dev == root->st_dev && st.st_ino == root->st_ino) {
if (!w2)
weprintf("\"/\" may not be removed\n");
w2 = 1;
return 1;
}
return 0;
}
int
main(int argc, char *argv[])
{
char *s;
struct stat st;
struct recursor r = { .fn = rm, .maxdepth = 1, .follow = 'P' };
ARGBEGIN {
@ -38,9 +73,14 @@ main(int argc, char *argv[])
return 0;
}
if (stat("/", &st) < 0)
eprintf("stat root:");
for (; *argv; argc--, argv++) {
if (strcmp(*argv, ".") && strcmp(*argv, ".."))
recurse(AT_FDCWD, *argv, NULL, &r);
if (forbidden(*argv, &st)) {
rm_status = 1;
continue;
}
recurse(AT_FDCWD, *argv, NULL, &r);
}
return rm_status || recurse_status;