Symlink-race-safe variant of do_utimensat() for receiver-side use. See the comment on do_chmod_at() for the threat model. utimes() resolves parent components and follows a final-component symlink; lutimes() doesn't follow the final component but still resolves parents. Either way, a parent-symlink swap can redirect the timestamp update outside the module. Defence: open the parent of pa
| 1384 | (caller is expected to fall back to the legacy tier walk). |
| 1385 | */ |
| 1386 | int do_utimensat_at(const char *path, STRUCT_STAT *stp) |
| 1387 | { |
| 1388 | #ifdef AT_FDCWD |
| 1389 | extern int am_daemon, am_chrooted; |
| 1390 | struct timespec t[2]; |
| 1391 | char dirpath[MAXPATHLEN]; |
| 1392 | const char *bname; |
| 1393 | const char *slash; |
| 1394 | int dfd, ret, e; |
| 1395 | size_t dlen; |
| 1396 | |
| 1397 | if (dry_run) return 0; |
| 1398 | RETURN_ERROR_IF_RO_OR_LO; |
| 1399 | |
| 1400 | if (!am_daemon || am_chrooted) |
| 1401 | return do_utimensat(path, stp); |
| 1402 | |
| 1403 | if (!path || !*path || *path == '/') |
| 1404 | return do_utimensat(path, stp); |
| 1405 | |
| 1406 | slash = strrchr(path, '/'); |
| 1407 | if (!slash) |
| 1408 | return do_utimensat(path, stp); |
| 1409 | |
| 1410 | dlen = slash - path; |
| 1411 | if (dlen >= sizeof dirpath) { |
| 1412 | errno = ENAMETOOLONG; |
| 1413 | return -1; |
| 1414 | } |
| 1415 | memcpy(dirpath, path, dlen); |
| 1416 | dirpath[dlen] = '\0'; |
| 1417 | bname = slash + 1; |
| 1418 | |
| 1419 | t[0].tv_sec = stp->st_atime; |
| 1420 | #ifdef ST_ATIME_NSEC |
| 1421 | t[0].tv_nsec = stp->ST_ATIME_NSEC; |
| 1422 | #else |
| 1423 | t[0].tv_nsec = 0; |
| 1424 | #endif |
| 1425 | t[1].tv_sec = stp->st_mtime; |
| 1426 | #ifdef ST_MTIME_NSEC |
| 1427 | t[1].tv_nsec = stp->ST_MTIME_NSEC; |
| 1428 | #else |
| 1429 | t[1].tv_nsec = 0; |
| 1430 | #endif |
| 1431 | |
| 1432 | dfd = secure_relative_open(NULL, dirpath, O_RDONLY | O_DIRECTORY, 0); |
| 1433 | if (dfd < 0) |
| 1434 | return -1; |
| 1435 | |
| 1436 | ret = utimensat(dfd, bname, t, AT_SYMLINK_NOFOLLOW); |
| 1437 | e = errno; |
| 1438 | close(dfd); |
| 1439 | errno = e; |
| 1440 | return ret; |
| 1441 | #else |
| 1442 | return do_utimensat(path, stp); |
| 1443 | #endif |
no test coverage detected