cybersecurity · intermediate · ~15 min
Encode the symlink + traversal refusal rule.
Encode the open-path refusal policy that models openat(..., O_NOFOLLOW) plus a path-traversal pre-check. The two prior checks have already run; this function is the AND combinator that joins them.
Implement int can_open_path_safely(const char *path, int last_is_symlink, int has_traversal) that returns 1 (safe to open) only when the path is non-empty and both checks pass.
Return 1 only if ALL hold:
path is non-NULL and non-empty;last_is_symlink == 0 (the final component is not a symlink);has_traversal == 0 (no .. segments).Otherwise return 0 (refused).
path: the candidate path string (or NULL/empty).last_is_symlink: 1 if the final component is a symlink (as O_NOFOLLOW would report via ELOOP), else 0.has_traversal: 1 if a .. segment was detected, else 0.Returns int: 1 if safe to open, 0 if refused.
can_open_path_safely("/var/data/file", 0, 0) -> 1
can_open_path_safely("/var/data/file", 1, 0) -> 0 (symlink)
can_open_path_safely("/var/data/../etc/passwd", 0, 1) -> 0 (traversal)
can_open_path_safely("/x", 1, 1) -> 0
can_open_path_safely(NULL, 0, 0) -> 0
NULL or empty path is refused.openat(dirfd, name, O_NOFOLLOW) returns ELOOP when the path is a symlink. Encoding that in a small policy lets you reason about the defence without a real filesystem.
A path string plus two flags: last_is_symlink and has_traversal.
An int: 1 if safe to open, 0 if refused.
Refuse on NULL/empty path or either flag set; pure boolean logic.
int can_open_path_safely(const char *path, int last_is_symlink, int has_traversal) { /* TODO */ (void)path; (void)last_is_symlink; (void)has_traversal; return 0; }
Returning 1 even when traversal is detected.
NULL path. Both flags set.
O(1).
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.