openUserFile attempts to open a file within the root fs. It handles cases where the file is an absolute symlink (e.g., NixOS /etc/passwd -> /nix/store/...), which triggers "path escapes from parent" errors in Go 1.24+ due to stricter os.DirFS validation. The returned file rejects non-regular source
(root fs.FS, name string)
| 1849 | // The returned file rejects non-regular sources and returns an error if more |
| 1850 | // than maxUserFileBytes are read from it. |
| 1851 | func openUserFile(root fs.FS, name string) (fs.File, error) { |
| 1852 | f, err := root.Open(name) |
| 1853 | if err == nil { |
| 1854 | return wrapUserFile(f, name) |
| 1855 | } |
| 1856 | |
| 1857 | // Check if the FS implements our local ReadLink interface. |
| 1858 | // We use a local interface instead of fs.ReadLinkFS to avoid strict dependency |
| 1859 | // issues in some build environments. |
| 1860 | if lfs, ok := root.(readLinker); ok { |
| 1861 | if target, lerr := lfs.ReadLink(name); lerr == nil { |
| 1862 | // Use filepath.IsAbs to handle platform-agnostic absolute path checks |
| 1863 | if filepath.IsAbs(target) { |
| 1864 | // Re-anchor the absolute path to the root. |
| 1865 | // e.g. /nix/store/... becomes nix/store/... (relative to root fs) |
| 1866 | // We use filepath.Rel to safely strip the leading separator. |
| 1867 | rel, rerr := filepath.Rel(string(filepath.Separator), target) |
| 1868 | if rerr == nil { |
| 1869 | // filepath.Rel might return OS-specific separators (backslashes on Windows). |
| 1870 | // fs.Open strictly expects forward slashes, so we convert it. |
| 1871 | f, oerr := root.Open(filepath.ToSlash(rel)) |
| 1872 | if oerr != nil { |
| 1873 | return nil, oerr |
| 1874 | } |
| 1875 | return wrapUserFile(f, name) |
| 1876 | } |
| 1877 | } |
| 1878 | } |
| 1879 | } |
| 1880 | |
| 1881 | // Return the original error if we couldn't resolve it |
| 1882 | return nil, err |
| 1883 | } |
| 1884 | |
| 1885 | // maxUserFileBytes caps how much data is read from any user-database file |
| 1886 | // opened via openUserFile. Real systems keep these files well under 1 MiB; |
searching dependent graphs…