MCPcopy Create free account
hub / github.com/RsyncProject/rsync / unsafe_symlink

Function unsafe_symlink

util1.c:1398–1453  ·  view source on GitHub ↗

Determine if a symlink points outside the current directory tree. * This is considered "unsafe" because e.g. when mirroring somebody * else's machine it might allow them to establish a symlink to * /etc/passwd, and then read it through a web server. * * Returns 1 if unsafe, 0 if safe. * * Null symlinks and absolute symlinks are always unsafe. * * Basically here we are concerned with symli

Source from the content-addressed store, hash-verified

1396 * resulting in the link being transferred now becoming unsafe
1397 */
1398int unsafe_symlink(const char *dest, const char *src)
1399{
1400 const char *name, *slash;
1401 int depth = 0;
1402
1403 /* all absolute and null symlinks are unsafe */
1404 if (!dest || !*dest || *dest == '/')
1405 return 1;
1406
1407 // reject destinations with /../ in the name other than at the start of the name
1408 const char *dest2 = dest;
1409 while (strncmp(dest2, "../", 3) == 0) {
1410 dest2 += 3;
1411 while (*dest2 == '/') {
1412 // allow for ..//..///../foo
1413 dest2++;
1414 }
1415 }
1416 if (strstr(dest2, "/../"))
1417 return 1;
1418
1419 // reject if the destination ends in /..
1420 const size_t dlen = strlen(dest);
1421 if (dlen > 3 && strcmp(&dest[dlen-3], "/..") == 0)
1422 return 1;
1423
1424 /* find out what our safety margin is */
1425 for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
1426 /* ".." segment starts the count over. "." segment is ignored. */
1427 if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
1428 if (name[1] == '.')
1429 depth = 0;
1430 } else
1431 depth++;
1432 while (slash[1] == '/') slash++; /* just in case src isn't clean */
1433 }
1434 if (*name == '.' && name[1] == '.' && name[2] == '\0')
1435 depth = 0;
1436
1437 for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
1438 if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
1439 if (name[1] == '.') {
1440 /* if at any point we go outside the current directory
1441 then stop - it is unsafe */
1442 if (--depth < 0)
1443 return 1;
1444 }
1445 } else
1446 depth++;
1447 while (slash[1] == '/') slash++;
1448 }
1449 if (*name == '.' && name[1] == '.' && name[2] == '\0')
1450 depth--;
1451
1452 return depth < 0;
1453}
1454
1455/* Return the date and time as a string. Some callers tweak returned buf. */

Callers 4

mainFunction · 0.85
make_backupFunction · 0.85
readlink_statFunction · 0.85
recv_generatorFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected