What is happening
hp-snare has been in a crash loop on the homeserver since roughly 2026-09-07 12:44. docker ps -a shows Restarting (1) and it never stays up long enough to serve.
snare-entrypoint: serving page-dir 'portal.meridian.example'
Traceback (most recent call last):
File "/usr/local/bin/snare", line 159, in <module>
snare_uuid = snare_setup(base_path)
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/bin/snare", line 54, in snare_setup
with open(os.path.join(base_path, 'snare.pid'), 'wb') as pid_fh:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: '/opt/snare/snare.pid'
No issue tracks this. A title search for snare returns only closed issues (#89, #124, #128, #557), none of which describe this failure.
Observed state
/opt/snare in the container is the bind mount /opt/stacks/apiary/logs/snare (arcane/home/honeypot-tanner/compose.yml:276). On the host:
drwxr-xrwx. 3 nobody nobody 133 Sep 4 01:34 .
-rw-r--r--. 1 nobody nobody 31 Sep 4 01:34 snare.cfg
-rw-r--r--. 1 nobody nobody 887 Sep 7 11:26 snare.err
-rw-r--r--. 1 nobody nobody 6216944 Sep 7 12:44 snare.log
-rw-r--r--. 1 nobody nobody 1 Sep 6 13:52 snare.pid
-rw-r--r--. 1 nobody nobody 36 Sep 4 01:34 snare.uuid
The directory is 0757 (other has write), so creating a new file there works. snare.pid already exists at 0644 owned by 65534:65534, so truncating that existing file requires either being uid 65534 or holding CAP_DAC_OVERRIDE.
The container has neither:
$ docker inspect hp-snare --format 'capdrop={{.HostConfig.CapDrop}} capadd={{.HostConfig.CapAdd}} user={{.Config.User}}'
capdrop=[ALL] capadd=[CAP_SETGID CAP_SETUID] user=
Config.User is empty and the image sets no USER, so the process is uid 0 at the point snare_setup() runs — SNARE drops privileges later, which is exactly why SETUID/SETGID are granted. Root without CAP_DAC_OVERRIDE cannot write another user's 0644 file. That is a consistent explanation for EACCES here, though it has not been proven by a direct test yet (see below).
Note that the compose comment immediately above the cap list records the opposite conclusion:
# SETUID+SETGID is the measured minimum; CHOWN and DAC_OVERRIDE were
# tested on top and changed nothing, so they are not granted.
That measurement was presumably taken on a first boot, when snare.pid did not yet exist and the other-writable directory let root create it. It does not hold once the file exists owned by another uid, which is the steady state after honeypot-init's chown -R 65534:65534 /logs/snare.
SELinux is Enforcing but ausearch -m avc -ts recent shows no snare denials, and the directory carries system_u:object_r:var_t:s0 identically to logs/tanner, whose containers run fine — so SELinux is not currently indicated as the cause. read_only: true is set on the service, but /opt/snare is a bind mount and is unaffected by it.
Blast radius
hp-snare is the HTTP front half of the Tanner stack — it serves the cloned persona pages and forwards every request to hp-tanner for emulation. While it loops, that sensor path captures nothing. The five sibling Tanner containers (hp-tanner, -web, -api, -redis, -docker, -phpox) are all Up 16 hours and healthy, so nothing else in the stack signals a problem — this is silent to every existing alarm.
Suggested fix direction
Two candidates, smallest first:
- Have the entrypoint remove the stale pid file before exec'ing snare (
rm -f /opt/snare/snare.pid) — creating it fresh works under the other-writable directory. Cheapest, no cap change.
- Grant
CAP_DAC_OVERRIDE and correct the compose comment that says it was tested and changed nothing.
Option 1 keeps the hardened cap set intact and is preferable if it holds. Either way the fix should be verified against a container that has been through at least one full restart cycle, not just a clean first boot — that is the exact gap that produced the misleading measurement in the comment.
Acceptance
Found during the round-10 issue audit.
What is happening
hp-snarehas been in a crash loop on the homeserver since roughly 2026-09-07 12:44.docker ps -ashowsRestarting (1)and it never stays up long enough to serve.No issue tracks this. A title search for
snarereturns only closed issues (#89, #124, #128, #557), none of which describe this failure.Observed state
/opt/snarein the container is the bind mount/opt/stacks/apiary/logs/snare(arcane/home/honeypot-tanner/compose.yml:276). On the host:The directory is
0757(otherhas write), so creating a new file there works.snare.pidalready exists at0644owned by65534:65534, so truncating that existing file requires either being uid 65534 or holdingCAP_DAC_OVERRIDE.The container has neither:
Config.Useris empty and the image sets noUSER, so the process is uid 0 at the pointsnare_setup()runs — SNARE drops privileges later, which is exactly whySETUID/SETGIDare granted. Root withoutCAP_DAC_OVERRIDEcannot write another user's0644file. That is a consistent explanation forEACCEShere, though it has not been proven by a direct test yet (see below).Note that the compose comment immediately above the cap list records the opposite conclusion:
That measurement was presumably taken on a first boot, when
snare.piddid not yet exist and theother-writable directory let root create it. It does not hold once the file exists owned by another uid, which is the steady state after honeypot-init'schown -R 65534:65534 /logs/snare.SELinux is
Enforcingbutausearch -m avc -ts recentshows nosnaredenials, and the directory carriessystem_u:object_r:var_t:s0identically tologs/tanner, whose containers run fine — so SELinux is not currently indicated as the cause.read_only: trueis set on the service, but/opt/snareis a bind mount and is unaffected by it.Blast radius
hp-snareis the HTTP front half of the Tanner stack — it serves the cloned persona pages and forwards every request tohp-tannerfor emulation. While it loops, that sensor path captures nothing. The five sibling Tanner containers (hp-tanner,-web,-api,-redis,-docker,-phpox) are allUp 16 hoursand healthy, so nothing else in the stack signals a problem — this is silent to every existing alarm.Suggested fix direction
Two candidates, smallest first:
rm -f /opt/snare/snare.pid) — creating it fresh works under theother-writable directory. Cheapest, no cap change.CAP_DAC_OVERRIDEand correct the compose comment that says it was tested and changed nothing.Option 1 keeps the hardened cap set intact and is preferable if it holds. Either way the fix should be verified against a container that has been through at least one full restart cycle, not just a clean first boot — that is the exact gap that produced the misleading measurement in the comment.
Acceptance
hp-snarestaysUpacross a deliberatedocker restartand a second one after it has written its pid fileEACCES, then show the chosen fix clears it)SETUID+SETGID is the measured minimumcomment inarcane/home/honeypot-tanner/compose.ymlreflects whatever the retest actually showsFound during the round-10 issue audit.