{"record":{"id":"0d2174675234ce95","repo":"kovidgoyal/kitty","slug":"incorrect-owner-on-shm-file","errorCode":null,"errorMessage":"Incorrect owner on SHM file","messagePattern":"Incorrect owner on SHM file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"kittens/ssh/main.go","lineNumber":78,"sourceCode":"\t\t\tif p.User.Username() != \"\" {\n\t\t\t\tusername = p.User.Username()\n\t\t\t}\n\t\t}\n\t} else if strings.Contains(hostname, \"@\") && hostname[0] != '@' {\n\t\tusername, hostname_for_match, _ = strings.Cut(hostname, \"@\")\n\t\tparsed = true\n\t}\n\tif !parsed && strings.Contains(hostname, \"@\") && hostname[0] != '@' {\n\t\t_, hostname_for_match, _ = strings.Cut(hostname, \"@\")\n\t}\n\treturn\n}\n\nfunc read_data_from_shared_memory(shm_name string) ([]byte, error) {\n\tdata, err := shm.ReadWithSizeAndUnlink(shm_name, func(s fs.FileInfo) error {\n\t\tif stat, ok := s.Sys().(syscall.Stat_t); ok {\n\t\t\tif os.Getuid() != int(stat.Uid) || os.Getgid() != int(stat.Gid) {\n\t\t\t\treturn fmt.Errorf(\"Incorrect owner on SHM file\")\n\t\t\t}\n\t\t}\n\t\tif s.Mode().Perm() != 0o600 {\n\t\t\treturn fmt.Errorf(\"Incorrect permissions on SHM file\")\n\t\t}\n\t\treturn nil\n\t})\n\treturn data, err\n}\n\nfunc add_cloned_env(val string) (ans map[string]string, err error) {\n\tdata, err := read_data_from_shared_memory(val)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = json.Unmarshal(data, &ans)\n\treturn ans, err\n}","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kittens/ssh/main.go#L60-L96","documentation":"The ssh kitten passes data to the bootstrap script via POSIX shared memory (/dev/shm). Before reading, it verifies the shm file's owner matches the current uid/gid; if not, this error is returned to prevent reading a file planted by another user (privilege escalation / data spoofing guard).","triggerScenarios":"read_data_from_shared_memory encountering a /dev/shm file owned by a different uid or gid than the current process — e.g. leftover file from a prior run under another user, or a file created by a setuid/sudo context.","commonSituations":"Running the kitten under sudo after a prior non-root run (or vice versa); container namespaces mapping different uids; shared machines where another user guessed the shm name; stale files in /dev/shm after a crash.","solutions":["Remove the stale shm file: ls -l /dev/shm/kitty.* then rm the offending one","Run the kitten consistently as the same user (avoid mixing sudo and normal runs)","Reboot or remount /dev/shm if stale files persist from a crashed session","Treat unexpected ownership as a security signal on multi-user hosts — investigate before deleting"],"exampleFix":"# before\nsudo kitty +kitten ssh user@host   # after a normal-user run left /dev/shm files\n# after (clean up and use one user)\nrm -f /dev/shm/kitty.*\nkitty +kitten ssh user@host","handlingStrategy":"try-catch","validationCode":"if info, err := os.Stat(shmPath); err == nil {\n    if st, ok := info.Sys().(*syscall.Stat_t); ok && int(st.Uid) != os.Getuid() {\n        // refuse and clean up before calling\n    }\n}","typeGuard":null,"tryCatchPattern":"if _, err := read_data_from_shared_memory(name); err != nil {\n    if strings.Contains(err.Error(), \"Incorrect owner\") {\n        os.Remove(shmPath) // stale from other-user run\n    }\n}","preventionTips":["Run the kitten under a single consistent user","Clean /dev/shm/kitty.* after crashes","Never run the kitten under sudo unless that is your only user context"],"tags":["ssh-kitten","shared-memory","security","permissions"],"backgroundTag":"shared-memory-ownership-check","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}