mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-10 09:13:53 +08:00
Review of the previous head reproduced a check-then-use window in the parent-chain walk: the link was judged by name (fstatat) and then opened by name (openat), with nothing tying the two to the same entry. An LD_PRELOAD shim that swaps the link for one pointing elsewhere the moment the judgement returns made both earlier heads follow the swapped link, including one owned by a foreign uid under root; the post-follow target check only bounds where such a swap can land. The link is now never opened by name after it has been judged. On Linux an O_PATH|O_NOFOLLOW descriptor pins the inode, fstat on that descriptor makes the ownership decision and readlinkat(fd, "") reads the target text from the same inode; on other systems the link is stat'ed by name before and after the readlinkat and both must be the same inode with the same owner. The walk then opens the text from the parent directory, so a relative text resolves against the link's own directory exactly as the kernel resolves it, and the target check runs on what that opens. The readlinkat form is used rather than /proc/self/fd so the walk does not depend on /proc being mounted. What is still done by path is resolving the text itself, which the target check bounds; the comment says so. Test: relative, ../, absolute and chained link texts resolve from the link's directory with the process CWD moved elsewhere. The race itself is exercised out of tree with the harness from the review thread. Refs #1722 Signed-off-by: TheStranjer <791672+TheStranjer@users.noreply.github.com>