On 11/30/2016 11:52 PM, Denys Vlasenko wrote:
On Wed, Nov 30, 2016 at 3:46 AM, Daniel Sabogal <dsaboga...@gmail.com> wrote:
The following commands cause busybox to segfault on musl-based systems.
$ install -D a /
$ install -D a /b
$ install -D a /b/
This happens because the code in
https://git.busybox.net/busybox/tree/coreutils/install.c?h=1_25_1#n196
passes the result of dirname() to bb_make_directory() which modifies its
contents. For paths of the above forms, musl's dirname returns a string
literal "/" which shouldn't be modified.
See http://git.musl-libc.org/cgit/musl/tree/src/misc/dirname.c
There are a few other occurrences of the code shown above, but I've not
checked to see if they could be made to segfault.
Does this fix the problem?
/* Bypass leading non-'/'s and then subsequent '/'s */
while (*s) {
if (*s == '/') {
do {
++s;
} while (*s == '/');
c = *s; /* Save the current char */
====added line==> if (c)
*s = '\0'; /* and
replace it with nul */
break;
_______________________________________________
Hi,
don't know if this could be useful, but reading this thread inspired
me to write dirname and basename replacement functions for busybox
that return a malloced string that could be modified by the caller.
The functions seem to work nice as standalone program and both
pass the tests as in the man 3 basename examples and a few more
added by me.
/* Man 3 BASENAME examples (taken from SUSv2)
path dirname basename
/usr/lib /usr lib
/usr/ / usr
usr . usr
/ / /
. . .
.. . ..
Added examples:
usr/lib usr lib
usr/lib/ usr lib
usr/ . usr
/usr . usr
/a/b/c /a/b c
/a/b/c/ /a/b c
a/b/c a/b c
a/b/c/ a/b c
// / /
/// / /
//// / /
'/a/b/ ' /a/b ' '
*/
The functions look like this:
char* bb_basename_malloc(const char *name)
{
const char *p1 = NULL;
const char *p2 = NULL;
const char *s = name;
char *last = last_char_is(s, '/');
while (*s) {
if (*s == '/') {
p2 = p1;
p1 = s;
}
s++;
}
if (last) {
if(p2)
name = p2 + 1;
} else if (p1) {
name = p1 + 1;
}
return xstrndup(name, strlen(name) - (last && last != name));
}
char* bb_dirname_malloc(const char *name)
{
int len = 0;
const char *p1 = NULL;
const char *p2 = NULL;
const char *s = name;
while (*s) {
if (*s == '/' && ((s[1] && s[1] != '/') || s == name)) {
p2 = p1;
p1 = s;
}
s++;
}
if (!p2 && !p1)
return xstrdup(".");
if (p1 == name && !p2)
return xstrdup("/");
if (p1)
len = strlen(p1);
return xstrndup(name, strlen(name) - len);
}
Attached you will find the standalone version to test the functions.
Hints, critics, improvements are welcome.
Ciao,
Tito
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char* xstrndup(const char *s, int n)
{
int m;
char *t;
// if (ENABLE_DEBUG && s == NULL)
// bb_error_msg_and_die("xstrndup bug");
/* We can just xmalloc(n+1) and strncpy into it, */
/* but think about xstrndup("abc", 10000) wastage! */
m = n;
t = (char*) s;
while (m) {
if (!*t) break;
m--;
t++;
}
n -= m;
t = malloc(n + 1);
t[n] = '\0';
return memcpy(t, s, n);
}
char* xstrdup(const char *s)
{
char *t;
if (s == NULL)
return NULL;
t = strdup(s);
if (t == NULL)
exit(1);
return t;
}
char* last_char_is(const char *s, int c)
{
if (s && *s) {
size_t sz = strlen(s) - 1;
s += sz;
if ( (unsigned char)*s == c)
return (char*)s;
}
return NULL;
}
char* bb_basename_malloc(const char *name)
{
const char *p1 = NULL;
const char *p2 = NULL;
const char *s = name;
char *last = last_char_is(s, '/');
while (*s) {
if (*s == '/') {
p2 = p1;
p1 = s;
}
s++;
}
if (last) {
if(p2)
name = p2 + 1;
} else if (p1) {
name = p1 + 1;
}
return xstrndup(name, strlen(name) - (last && last != name));
}
char* bb_dirname_malloc(const char *name)
{
int len = 0;
const char *p1 = NULL;
const char *p2 = NULL;
const char *s = name;
while (*s) {
if (*s == '/' && ((s[1] && s[1] != '/') || s == name)) {
p2 = p1;
p1 = s;
}
s++;
}
if (!p2 && !p1)
return xstrdup(".");
if (p1 == name && !p2)
return xstrdup("/");
if (p1)
len = strlen(p1);
return xstrndup(name, strlen(name) - len);
}
/* Man 3 BASENAME examples (taken from SUSv2)
path dirname basename
/usr/lib /usr lib
/usr/ / usr
usr . usr
/ / /
. . .
.. . ..
Added examples:
usr/lib usr lib
usr/lib/ usr lib
usr/ . usr
/usr . usr
/a/b/c /a/b c
/a/b/c/ /a/b c
a/b/c a/b c
a/b/c/ a/b c
// / /
/// / /
//// / /
'/a/b/ ' /a/b ' '
*/
int main(int argc, char ** argv)
{
char *dname = bb_dirname_malloc( "/usr/lib");
char *bname = bb_basename_malloc("/usr/lib");
printf("test 1 dirname %s\texpected %s\tresult %s = %s\n", "/usr/lib" , "/usr", dname, (strcmp(dname, "/usr") == 0) ? "PASSED" : "FAILED");
printf("test 1 basename %s\texpected %s\tresult %s = %s\n\n", "/usr/lib" , "lib" , bname, (strcmp(bname, "lib") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("/usr/");
bname = bb_basename_malloc("/usr/");
printf("test 2 dirname %s\t\texpected %s\tresult %s = %s\n", "/usr/" , "/" , dname, (strcmp(dname, "/") == 0) ? "PASSED" : "FAILED");
printf("test 2 basename %s\t\texpected %s\tresult %s = %s\n\n", "/usr/" , "usr" , bname, (strcmp(bname, "usr") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("usr");
bname = bb_basename_malloc("usr");
printf("test 3 dirname %s\t\texpected %s\tresult %s = %s\n", "usr", "." , dname, (strcmp(dname, ".") == 0) ? "PASSED" : "FAILED");
printf("test 3 basename %s\t\texpected %s\tresult %s = %s\n\n", "usr", "usr" , bname, (strcmp(bname, "usr") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("/");
bname = bb_basename_malloc("/");
printf("test 4 dirname %s\t\texpected %s\tresult %s = %s\n", "/", "/", dname, (strcmp(dname, "/") == 0) ? "PASSED" : "FAILED");
printf("test 4 basename %s\t\texpected %s\tresult %s = %s\n\n", "/", "/" ,bname, (strcmp(bname, "/") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc(".");
bname = bb_basename_malloc(".");
printf("test 5 dirname %s\t\texpected %s\tresult %s = %s\n", ".", ".", dname, (strcmp(dname, ".") == 0) ? "PASSED" : "FAILED");
printf("test 5 basename %s\t\texpected %s\tresult %s = %s\n\n", ".", ".", bname, (strcmp(bname, ".") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("..");
bname = bb_basename_malloc("..");
printf("test 6 dirname %s\t\texpected %s\tresult %s = %s\n", "..", ".", dname, (strcmp(dname, ".") == 0) ? "PASSED" : "FAILED");
printf("test 6 basename %s\t\texpected %s\tresult %s = %s\n\n", "..", "..", bname, (strcmp(bname, "..") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("usr/lib");
bname = bb_basename_malloc("usr/lib");
printf("test 7 dirname %s\t\texpected %s\tresult %s = %s\n", "usr/lib", "usr", dname, (strcmp(dname, "usr") == 0) ? "PASSED" : "FAILED");
printf("test 7 basename %s\t\texpected %s\tresult %s = %s\n\n", "usr/lib", "lib", bname, (strcmp(bname, "lib") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("usr/lib/");
bname = bb_basename_malloc("usr/lib/");
printf("test 8 dirname %s\texpected %s\tresult %s = %s\n", "usr/lib/", "usr", dname, (strcmp(dname, "usr") == 0) ? "PASSED" : "FAILED");
printf("test 8 basename %s\texpected %s\tresult %s = %s\n\n", "usr/lib/", "lib", bname, (strcmp(bname, "lib") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("");
bname = bb_basename_malloc("");
printf("test 9 dirname %s\t\texpected %s\tresult %s = %s\n", "", ".", dname, (strcmp(dname, ".") == 0) ? "PASSED" : "FAILED");
printf("test 9 basename %s\t\texpected %s\tresult %s = %s\n\n", "", "", bname, (strcmp(bname, "") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("usr/");
bname = bb_basename_malloc("usr/");
printf("test10 dirname %s\t\texpected %s\tresult %s = %s\n", "usr/", ".", dname, (strcmp(dname, ".") == 0) ? "PASSED" : "FAILED");
printf("test10 basename %s\t\texpected %s\tresult %s = %s\n\n", "usr/", "usr", bname, (strcmp(bname, "usr") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("/usr");
bname = bb_basename_malloc("/usr");
printf("test11 dirname %s\t\texpected %s\tresult %s = %s\n", "/usr", "/", dname, (strcmp(dname, "/") == 0) ? "PASSED" : "FAILED");
printf("test11 basename %s\t\texpected %s\tresult %s = %s\n\n", "/usr", "usr", bname, (strcmp(bname, "usr") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("/a/b/c");
bname = bb_basename_malloc("/a/b/c");
printf("test12 dirname %s\texpected %s result %s = %s\n", "/a/b/c", "/a/b", dname, (strcmp(dname, "/a/b") == 0) ? "PASSED" : "FAILED");
printf("test12 basename %s\texpected %s result %s = %s\n\n", "/a/b/b", "c", bname, (strcmp(bname, "c") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("/usr/local/bin");
bname = bb_basename_malloc("/usr/local/bin");
printf("test13 dirname %s\texpected %s result %s = %s\n", "/usr/local/bin", "/usr/local", dname, (strcmp(dname, "/usr/local") == 0) ? "PASSED" : "FAILED");
printf("test13 basename %s\texpected %s result %s = %s\n\n", "/usr/local/bin", "bin", bname, (strcmp(bname, "bin") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("/usr/local/bin/");
bname = bb_basename_malloc("/usr/local/bin/");
printf("test14 dirname %s\texpected %s result %s = %s\n", "/usr/local/bin/", "/usr/local", dname, (strcmp(dname, "/usr/local") == 0) ? "PASSED" : "FAILED");
printf("test14 basename %s\texpected %s result %s = %s\n\n", "/usr/local/bin/", "bin", bname, (strcmp(bname, "bin") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("usr/local/bin");
bname = bb_basename_malloc("usr/local/bin");
printf("test15 dirname %s\texpected %s result %s = %s\n", "usr/local/bin", "usr/local", dname, (strcmp(dname, "usr/local") == 0) ? "PASSED" : "FAILED");
printf("test15 basename %s\texpected %s result %s = %s\n\n", "usr/local/bin", "bin", bname, (strcmp(bname, "bin") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("usr/local/bin/");
bname = bb_basename_malloc("usr/local/bin/");
printf("test16 dirname %s\texpected %s result %s = %s\n", "usr/local/bin", "usr/local", dname, (strcmp(dname, "usr/local") == 0) ? "PASSED" : "FAILED");
printf("test16 basename %s\texpected %s result %s = %s\n\n", "usr/local/bin", "bin", bname, (strcmp(bname, "bin") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("//");
bname = bb_basename_malloc("//");
printf("test17 dirname %s\texpected %s result %s = %s\n", "//", "/", dname, (strcmp(dname, "/") == 0) ? "PASSED" : "FAILED");
printf("test17 basename %s\texpected %s result %s = %s\n\n", "//", "/", bname, (strcmp(bname, "/") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("///");
bname = bb_basename_malloc("///");
printf("test18 dirname %s\texpected %s result %s = %s\n", "///", "/", dname, (strcmp(dname, "/") == 0) ? "PASSED" : "FAILED");
printf("test18 basename %s\texpected %s result %s = %s\n\n", "///", "/", bname, (strcmp(bname, "/") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("////");
bname = bb_basename_malloc("////");
printf("test19 dirname %s\texpected %s result %s = %s\n", "////", "/", dname, (strcmp(dname, "/") == 0) ? "PASSED" : "FAILED");
printf("test19 basename %s\texpected %s result %s = %s\n\n", "////", "/", bname, (strcmp(bname, "/") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
dname = bb_dirname_malloc("/a/b/ ");
bname = bb_basename_malloc("/a/b/ ");
printf("test20 dirname %s\texpected %s result %s = %s\n", "/a/b/ ", "/a/b", dname, (strcmp(dname, "/a/b") == 0) ? "PASSED" : "FAILED");
printf("test20 basename %s\texpected %s result %s = %s\n\n", "/a/b/ ", " ", bname, (strcmp(bname, " ") == 0) ? "PASSED" : "FAILED");
free(dname);
free(bname);
return 0;
}
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox