// SPDX-License-Identifier: GPL-3.0-or-later package system import ( "os" "path/filepath" "sort" "syscall" ) // ScanSUIDBinaries mirrors Python's deliberately conservative SUID/SGID walk. // The primary root never crosses a filesystem boundary, while explicitly // configured writable mounts are walked separately because tmpfs-backed paths // are exactly where an attacker is likely to drop a privileged binary. // // Individual unreadable entries are ignored. Host filesystems are inherently // racy and permission-sensitive, so one denied subtree must not discard the // useful portion of a scan. func ScanSUIDBinaries(root string, extraDirs []string) []string { if root == "" { root = "/" } result := make(map[string]bool) rootInfo, err := os.Lstat(root) if err == nil { device, ok := deviceID(rootInfo) if ok { walkSUID(root, &device, result) } } for _, directory := range extraDirs { info, err := os.Lstat(directory) if err != nil || !info.IsDir() { continue } walkSUID(directory, nil, result) } paths := make([]string, 0, len(result)) for path := range result { paths = append(paths, path) } sort.Strings(paths) return paths } func walkSUID(root string, requiredDevice *uint64, result map[string]bool) { stack := []string{root} for len(stack) > 0 { directory := stack[len(stack)-1] stack = stack[:len(stack)-1] entries, err := os.ReadDir(directory) if err != nil { continue } for _, entry := range entries { path := filepath.Join(directory, entry.Name()) info, err := os.Lstat(path) if err != nil { continue } if info.IsDir() { if requiredDevice != nil { device, ok := deviceID(info) if !ok || device != *requiredDevice { continue } } stack = append(stack, path) continue } mode := info.Mode() if mode.IsRegular() && (mode&os.ModeSetuid != 0 || mode&os.ModeSetgid != 0) { result[path] = true } } } } func deviceID(info os.FileInfo) (uint64, bool) { stat, ok := info.Sys().(*syscall.Stat_t) if !ok { return 0, false } return uint64(stat.Dev), true }