)]}'
{"id":"depot~13866","triplet_id":"depot~canon~Ia5a97f105697786d6207a9b45f4224effb087203","project":"depot","branch":"canon","attention_set":{},"removed_from_attention_set":{"1000034":{"account":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"last_update":"2026-03-14 14:45:03.000000000","reason":"Removed by \u003cGERRIT_ACCOUNT_1000034\u003e by clicking the attention icon","reason_account":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"}},"1000001":{"account":{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"},"last_update":"2025-12-30 15:38:01.000000000","reason":"removed on reply"}},"hashtags":[],"change_id":"Ia5a97f105697786d6207a9b45f4224effb087203","subject":"fix(3p/cppnix): Fix long paths permanently breaking GC","status":"NEW","created":"2025-11-16 14:15:11.000000000","updated":"2026-03-14 14:45:03.000000000","submit_type":"REBASE_ALWAYS","submittable":true,"total_comment_count":0,"unresolved_comment_count":0,"has_review_started":true,"meta_rev_id":"111342a700c239ca4ce648827c22836f4ccdf05d","_number":13866,"virtual_id_number":13866,"owner":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"actions":{},"labels":{"Code-Review":{"approved":{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"},"all":[{"value":2,"date":"2025-12-30 15:38:01.000000000","permitted_voting_range":{"min":-2,"max":2},"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"},{"value":0,"permitted_voting_range":{"min":-1,"max":1},"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]}],"values":{"-2":"This shall not be merged","-1":"I would prefer this is not merged as is"," 0":"No score","+1":"Looks good to me, but someone else must approve","+2":"Looks good to me, approved"},"description":"","default_value":0},"Verified":{"approved":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"all":[{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"},{"tag":"autogenerated:buildkite~result","value":1,"date":"2025-12-10 22:42:49.000000000","permitted_voting_range":{"min":-1,"max":1},"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]}],"values":{"-1":"Fails"," 0":"No score","+1":"Verified"},"description":"","default_value":0},"Autosubmit":{"all":[{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"},{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]}],"values":{" 0":"Submit manually","+1":"Submit automatically"},"description":"","default_value":0,"optional":true},"All-Comments-Resolved":{"approved":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"}},"Conformant-Commit-Message":{"approved":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"}}},"removable_reviewers":[],"reviewers":{"CC":[{"_account_id":1000018,"name":"Alyssa Ross","display_name":"qyliss","email":"hi@alyssa.is","username":"qyliss"}],"REVIEWER":[{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"},{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]}]},"pending_reviewers":{},"reviewer_updates":[{"updated":"2025-11-16 14:15:11.000000000","updated_by":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"reviewer":{"_account_id":1000018,"name":"Alyssa Ross","display_name":"qyliss","email":"hi@alyssa.is","username":"qyliss"},"state":"CC"},{"updated":"2025-11-16 14:15:14.000000000","updated_by":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"reviewer":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"state":"CC"},{"updated":"2025-11-16 14:28:09.000000000","updated_by":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"reviewer":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"state":"REVIEWER"},{"updated":"2025-11-16 14:49:33.000000000","updated_by":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"reviewer":{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"},"state":"REVIEWER"}],"messages":[{"id":"03a0ee45c92ddaec1a725aec9c19c160a0c9eb1b","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"date":"2025-11-16 14:15:11.000000000","message":"Uploaded patch set 1.","accounts_in_message":[],"_revision_number":1},{"id":"6e9e745395755d9bd986f9b2a7a9f40d8d89ad38","tag":"autogenerated:buildkite~trigger","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-11-16 14:15:14.000000000","message":"Patch Set 1:\n\nStarted build for patchset #1 on: https://buildkite.com/tvl/depot/builds/40635","accounts_in_message":[],"_revision_number":1},{"id":"83c4c85052de39bb58631eba30ee1ce2bf2ac8ac","tag":"autogenerated:buildkite~result","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-11-16 14:28:09.000000000","message":"Patch Set 1: Verified-1\n\nBuild of patchset 1 failed: https://buildkite.com/tvl/depot/builds/40635","accounts_in_message":[],"_revision_number":1},{"id":"8ac7e842e80b3c7e8d8674074de11f816cdf0090","tag":"autogenerated:buildkite~result","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-11-16 14:43:47.000000000","message":"Patch Set 1: Verified+1\n\nBuild of patchset 1 passed: https://buildkite.com/tvl/depot/builds/40641","accounts_in_message":[],"_revision_number":1},{"id":"734b772b3e92d008753228df7461ea9daf16af90","tag":"autogenerated:gerrit:code-owners:addReviewer","author":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"date":"2025-11-16 14:49:33.000000000","message":"\u003cGERRIT_ACCOUNT_1000001\u003e, who was added as reviewer owns the following files:\n* `third_party/cppnix/src/libutil/util.cc`\n","accounts_in_message":[{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"}],"_revision_number":1},{"id":"a5b75af7cde356485bf60e8229ba4d09566fa5a2","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"date":"2025-11-16 18:05:32.000000000","message":"Uploaded patch set 2: New patch set was added with same tree, parent tree, and commit message as Patch Set 1.\n\nCopied Votes:\n* Verified+1 (copy condition: \"(**is:ANY** AND **changekind:NO_CODE_CHANGE**) OR **changekind:NO_CHANGE**\")\n","accounts_in_message":[],"_revision_number":2},{"id":"738470ab9d5390382bbd37a334395832383e9308","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"date":"2025-11-16 18:45:03.000000000","message":"Uploaded patch set 3: Patch Set 2 was rebased.\n\nOutdated Votes:\n* Verified+1 (copy condition: \"(**is:ANY** AND changekind:NO_CODE_CHANGE) OR changekind:NO_CHANGE\")\n","accounts_in_message":[],"_revision_number":3},{"id":"54126ff7ea5f39957b5ab4e6fd1e41e46089fbf3","tag":"autogenerated:buildkite~trigger","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-11-16 18:45:12.000000000","message":"Patch Set 3:\n\nStarted build for patchset #3 on: https://buildkite.com/tvl/depot/builds/40661","accounts_in_message":[],"_revision_number":3},{"id":"6f3486debae38b1e7baa080b75c0af20fa3dab8e","tag":"autogenerated:buildkite~result","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-11-16 19:16:19.000000000","message":"Patch Set 3: Verified-1\n\nBuild of patchset 3 failed: https://buildkite.com/tvl/depot/builds/40661","accounts_in_message":[],"_revision_number":3},{"id":"307b27f34485f2c28e896edb1b3d495600534388","tag":"autogenerated:buildkite~result","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-11-16 19:31:57.000000000","message":"Patch Set 3: Verified+1\n\nBuild of patchset 3 passed: https://buildkite.com/tvl/depot/builds/40669","accounts_in_message":[],"_revision_number":3},{"id":"7d7a7a13f08766f872112341781f98720f5f72cd","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"date":"2025-11-16 21:37:13.000000000","message":"Uploaded patch set 4: Patch Set 3 was rebased.\n\nOutdated Votes:\n* Verified+1 (copy condition: \"(**is:ANY** AND changekind:NO_CODE_CHANGE) OR changekind:NO_CHANGE\")\n","accounts_in_message":[],"_revision_number":4},{"id":"2ee5e0c0ebb05da6884b84dd245af1eae0dde6f8","tag":"autogenerated:buildkite~trigger","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-11-16 21:37:21.000000000","message":"Patch Set 4:\n\nStarted build for patchset #4 on: https://buildkite.com/tvl/depot/builds/40690","accounts_in_message":[],"_revision_number":4},{"id":"17c62c428983dec19848186baf863ab314e2de40","tag":"autogenerated:buildkite~result","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-11-16 22:00:33.000000000","message":"Patch Set 4: Verified+1\n\nBuild of patchset 4 passed: https://buildkite.com/tvl/depot/builds/40690","accounts_in_message":[],"_revision_number":4},{"id":"af9b74c4d4e955034fe5247b61d62d9fdb238238","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"date":"2025-12-10 22:31:02.000000000","message":"Uploaded patch set 5: Patch Set 4 was rebased.\n\nOutdated Votes:\n* Verified+1 (copy condition: \"(**is:ANY** AND changekind:NO_CODE_CHANGE) OR changekind:NO_CHANGE\")\n","accounts_in_message":[],"_revision_number":5},{"id":"c96ca482f862cad24bae150777c17ad07600d1a0","tag":"autogenerated:buildkite~trigger","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-12-10 22:31:08.000000000","message":"Patch Set 5:\n\nStarted build for patchset #5 on: https://buildkite.com/tvl/depot/builds/40779","accounts_in_message":[],"_revision_number":5},{"id":"43e520cd37e70a299b38b64b77576e35aa744875","tag":"autogenerated:buildkite~result","author":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]},"date":"2025-12-10 22:42:49.000000000","message":"Patch Set 5: Verified+1\n\nBuild of patchset 5 passed: https://buildkite.com/tvl/depot/builds/40779","accounts_in_message":[],"_revision_number":5},{"id":"f097d5f41ecbce2d134f74f766ad24111477b5bc","author":{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"},"date":"2025-12-30 15:38:01.000000000","message":"Patch Set 5: Code-Review+2","accounts_in_message":[],"_revision_number":5}],"current_revision_number":5,"current_revision":"a36e66049ceb15532353949edfca3e03e010319d","revisions":{"c0f14c0ff9457eb4e3987131aa009bba77342795":{"kind":"REWORK","_number":1,"created":"2025-11-16 14:15:11.000000000","uploader":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"ref":"refs/changes/66/13866/1","fetch":{"anonymous http":{"url":"https://cl.tvl.fyi/depot","ref":"refs/changes/66/13866/1","commands":{"Checkout":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/1 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/1 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/1 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://cl.tvl.fyi/depot refs/changes/66/13866/1"}}},"commit":{"parents":[{"commit":"e3942ccd525791a0979d61e6d7e598286ccbf056","subject":"fix(cppnix/libstore): ensure `passAsFile` is created in orig tmpdir","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003de3942ccd525791a0979d61e6d7e598286ccbf056"}]}],"author":{"name":"Alyssa Ross","email":"hi@alyssa.is","date":"2020-04-27 14:15:15.000000000","tz":0},"committer":{"name":"sterni","email":"sternenseemann@systemli.org","date":"2025-11-16 14:09:12.000000000","tz":60},"subject":"fix(3p/cppnix): Fix long paths permanently breaking GC","message":"fix(3p/cppnix): Fix long paths permanently breaking GC\n\nSuppose I have a path /nix/store/[hash]-[name]/a/a/a/a/a/[...]/a,\nlong enough that everything after \"/nix/store/\" is longer than 4096\n(MAX_PATH) bytes.\n\nNix will happily allow such a path to be inserted into the store,\nbecause it doesn\u0027t look at all the nested structure.  It just cares\nabout the /nix/store/[hash]-[name] part.  But, when the path is deleted,\nwe encounter a problem.  Nix will move the path to /nix/store/trash, but\nthen when it\u0027s trying to recursively delete the trash directory, it will\nat some point try to unlink\n/nix/store/trash/[hash]-[name]/a/a/a/a/a/[...]/a.  This will fail,\nbecause the path is too long.  After this has failed, any store deletion\noperation will never work again, because Nix needs to delete the trash\ndirectory before recreating it to move new things to it.  (I assume this\nis because otherwise a path being deleted could already exist in the\ntrash, and then moving it would fail.)\n\nThis means that if I can trick somebody into just fetching a tarball\ncontaining a path of the right length, they won\u0027t be able to delete\nstore paths or garbage collect ever again, until the offending path is\nmanually removed from /nix/store/trash.  (And even fixing this manually\nis quite difficult if you don\u0027t understand the issue, because the\nabsolute path that Nix says it failed to remove is also too long for\nrm(1).)\n\nThis patch fixes the issue by making Nix\u0027s recursive delete operation\nuse unlinkat(2).  This function takes a relative path and a directory\nfile descriptor.  We ensure that the relative path is always just the\nname of the directory entry, and therefore its length will never exceed\n255 bytes.  This means that it will never even come close to AX_PATH,\nand Nix will therefore be able to handle removing arbitrarily deep\ndirectory hierachies.\n\nSince the directory file descriptor is used for recursion after being\nused in readDirectory, I made a variant of readDirectory that takes an\nalready open directory stream, to avoid the directory being opened\nmultiple times.  As we have seen from this issue, the less we have to\ninteract with paths, the better, and so it\u0027s good to reuse file\ndescriptors where possible.\n\nI left _deletePath as succeeding even if the parent directory doesn\u0027t\nexist, even though that feels wrong to me, because without that early\nreturn, the linux-sandbox test failed.\n\nReported-by: Alyssa Ross \u003chi@alyssa.is\u003e\nThanks-to: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nTested-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nReviewed-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nChange-Id: Ia5a97f105697786d6207a9b45f4224effb087203\n","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003dc0f14c0ff9457eb4e3987131aa009bba77342795"}],"resolve_conflicts_web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003dc0f14c0ff9457eb4e3987131aa009bba77342795"}]},"parents_data":[{"branch_name":"refs/heads/canon","commit_id":"e3942ccd525791a0979d61e6d7e598286ccbf056","is_merged_in_target_branch":false,"change_id":"Ie5273446c4a19403088d0389ae8e3f473af8879a","change_number":13865,"patch_set_number":1,"change_status":"NEW"}],"branch":"refs/heads/canon"},"abba4e2b8371bffc89e28c21bca29daad5253412":{"kind":"NO_CHANGE","_number":2,"created":"2025-11-16 18:05:32.000000000","uploader":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"ref":"refs/changes/66/13866/2","fetch":{"anonymous http":{"url":"https://cl.tvl.fyi/depot","ref":"refs/changes/66/13866/2","commands":{"Checkout":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/2 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/2 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/2 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://cl.tvl.fyi/depot refs/changes/66/13866/2"}}},"commit":{"parents":[{"commit":"d3f8cb2bc3af1d492200a499242b38d710182c7b","subject":"fix(cppnix/libstore): ensure `passAsFile` is created in orig tmpdir","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003dd3f8cb2bc3af1d492200a499242b38d710182c7b"}]}],"author":{"name":"Alyssa Ross","email":"hi@alyssa.is","date":"2020-04-27 14:15:15.000000000","tz":0},"committer":{"name":"sterni","email":"sternenseemann@systemli.org","date":"2025-11-16 18:05:28.000000000","tz":60},"subject":"fix(3p/cppnix): Fix long paths permanently breaking GC","message":"fix(3p/cppnix): Fix long paths permanently breaking GC\n\nSuppose I have a path /nix/store/[hash]-[name]/a/a/a/a/a/[...]/a,\nlong enough that everything after \"/nix/store/\" is longer than 4096\n(MAX_PATH) bytes.\n\nNix will happily allow such a path to be inserted into the store,\nbecause it doesn\u0027t look at all the nested structure.  It just cares\nabout the /nix/store/[hash]-[name] part.  But, when the path is deleted,\nwe encounter a problem.  Nix will move the path to /nix/store/trash, but\nthen when it\u0027s trying to recursively delete the trash directory, it will\nat some point try to unlink\n/nix/store/trash/[hash]-[name]/a/a/a/a/a/[...]/a.  This will fail,\nbecause the path is too long.  After this has failed, any store deletion\noperation will never work again, because Nix needs to delete the trash\ndirectory before recreating it to move new things to it.  (I assume this\nis because otherwise a path being deleted could already exist in the\ntrash, and then moving it would fail.)\n\nThis means that if I can trick somebody into just fetching a tarball\ncontaining a path of the right length, they won\u0027t be able to delete\nstore paths or garbage collect ever again, until the offending path is\nmanually removed from /nix/store/trash.  (And even fixing this manually\nis quite difficult if you don\u0027t understand the issue, because the\nabsolute path that Nix says it failed to remove is also too long for\nrm(1).)\n\nThis patch fixes the issue by making Nix\u0027s recursive delete operation\nuse unlinkat(2).  This function takes a relative path and a directory\nfile descriptor.  We ensure that the relative path is always just the\nname of the directory entry, and therefore its length will never exceed\n255 bytes.  This means that it will never even come close to AX_PATH,\nand Nix will therefore be able to handle removing arbitrarily deep\ndirectory hierachies.\n\nSince the directory file descriptor is used for recursion after being\nused in readDirectory, I made a variant of readDirectory that takes an\nalready open directory stream, to avoid the directory being opened\nmultiple times.  As we have seen from this issue, the less we have to\ninteract with paths, the better, and so it\u0027s good to reuse file\ndescriptors where possible.\n\nI left _deletePath as succeeding even if the parent directory doesn\u0027t\nexist, even though that feels wrong to me, because without that early\nreturn, the linux-sandbox test failed.\n\nReported-by: Alyssa Ross \u003chi@alyssa.is\u003e\nThanks-to: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nTested-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nReviewed-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nChange-Id: Ia5a97f105697786d6207a9b45f4224effb087203\n","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003dabba4e2b8371bffc89e28c21bca29daad5253412"}],"resolve_conflicts_web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003dabba4e2b8371bffc89e28c21bca29daad5253412"}]},"parents_data":[{"branch_name":"refs/heads/canon","commit_id":"d3f8cb2bc3af1d492200a499242b38d710182c7b","is_merged_in_target_branch":false,"change_id":"Ie5273446c4a19403088d0389ae8e3f473af8879a","change_number":13865,"patch_set_number":2,"change_status":"NEW"}],"branch":"refs/heads/canon"},"1df3cc67f19a64e94cb562d52114583d4f73ddeb":{"kind":"TRIVIAL_REBASE","_number":3,"created":"2025-11-16 18:45:03.000000000","uploader":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"ref":"refs/changes/66/13866/3","fetch":{"anonymous http":{"url":"https://cl.tvl.fyi/depot","ref":"refs/changes/66/13866/3","commands":{"Checkout":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/3 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/3 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/3 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://cl.tvl.fyi/depot refs/changes/66/13866/3"}}},"commit":{"parents":[{"commit":"6fc60f3e3121b1480ba9fca13e807210c4b2e2a0","subject":"fix(cppnix/libstore): ensure `passAsFile` is created in orig tmpdir","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003d6fc60f3e3121b1480ba9fca13e807210c4b2e2a0"}]}],"author":{"name":"Alyssa Ross","email":"hi@alyssa.is","date":"2020-04-27 14:15:15.000000000","tz":0},"committer":{"name":"sterni","email":"sternenseemann@systemli.org","date":"2025-11-16 18:44:53.000000000","tz":60},"subject":"fix(3p/cppnix): Fix long paths permanently breaking GC","message":"fix(3p/cppnix): Fix long paths permanently breaking GC\n\nSuppose I have a path /nix/store/[hash]-[name]/a/a/a/a/a/[...]/a,\nlong enough that everything after \"/nix/store/\" is longer than 4096\n(MAX_PATH) bytes.\n\nNix will happily allow such a path to be inserted into the store,\nbecause it doesn\u0027t look at all the nested structure.  It just cares\nabout the /nix/store/[hash]-[name] part.  But, when the path is deleted,\nwe encounter a problem.  Nix will move the path to /nix/store/trash, but\nthen when it\u0027s trying to recursively delete the trash directory, it will\nat some point try to unlink\n/nix/store/trash/[hash]-[name]/a/a/a/a/a/[...]/a.  This will fail,\nbecause the path is too long.  After this has failed, any store deletion\noperation will never work again, because Nix needs to delete the trash\ndirectory before recreating it to move new things to it.  (I assume this\nis because otherwise a path being deleted could already exist in the\ntrash, and then moving it would fail.)\n\nThis means that if I can trick somebody into just fetching a tarball\ncontaining a path of the right length, they won\u0027t be able to delete\nstore paths or garbage collect ever again, until the offending path is\nmanually removed from /nix/store/trash.  (And even fixing this manually\nis quite difficult if you don\u0027t understand the issue, because the\nabsolute path that Nix says it failed to remove is also too long for\nrm(1).)\n\nThis patch fixes the issue by making Nix\u0027s recursive delete operation\nuse unlinkat(2).  This function takes a relative path and a directory\nfile descriptor.  We ensure that the relative path is always just the\nname of the directory entry, and therefore its length will never exceed\n255 bytes.  This means that it will never even come close to AX_PATH,\nand Nix will therefore be able to handle removing arbitrarily deep\ndirectory hierachies.\n\nSince the directory file descriptor is used for recursion after being\nused in readDirectory, I made a variant of readDirectory that takes an\nalready open directory stream, to avoid the directory being opened\nmultiple times.  As we have seen from this issue, the less we have to\ninteract with paths, the better, and so it\u0027s good to reuse file\ndescriptors where possible.\n\nI left _deletePath as succeeding even if the parent directory doesn\u0027t\nexist, even though that feels wrong to me, because without that early\nreturn, the linux-sandbox test failed.\n\nReported-by: Alyssa Ross \u003chi@alyssa.is\u003e\nThanks-to: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nTested-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nReviewed-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nChange-Id: Ia5a97f105697786d6207a9b45f4224effb087203\n","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003d1df3cc67f19a64e94cb562d52114583d4f73ddeb"}],"resolve_conflicts_web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003d1df3cc67f19a64e94cb562d52114583d4f73ddeb"}]},"parents_data":[{"branch_name":"refs/heads/canon","commit_id":"6fc60f3e3121b1480ba9fca13e807210c4b2e2a0","is_merged_in_target_branch":false,"change_id":"Ie5273446c4a19403088d0389ae8e3f473af8879a","change_number":13865,"patch_set_number":3,"change_status":"NEW"}],"branch":"refs/heads/canon"},"9d78db4d9d094f4d93989c4291dcc378b371e291":{"kind":"TRIVIAL_REBASE","_number":4,"created":"2025-11-16 21:37:13.000000000","uploader":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"ref":"refs/changes/66/13866/4","fetch":{"anonymous http":{"url":"https://cl.tvl.fyi/depot","ref":"refs/changes/66/13866/4","commands":{"Checkout":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/4 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/4 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/4 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://cl.tvl.fyi/depot refs/changes/66/13866/4"}}},"commit":{"parents":[{"commit":"7a6aa644adb92c224b004867a1846d13c70376c6","subject":"fix(cppnix/libstore): ensure `passAsFile` is created in orig tmpdir","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003d7a6aa644adb92c224b004867a1846d13c70376c6"}]}],"author":{"name":"Alyssa Ross","email":"hi@alyssa.is","date":"2020-04-27 14:15:15.000000000","tz":0},"committer":{"name":"sterni","email":"sternenseemann@systemli.org","date":"2025-11-16 21:37:08.000000000","tz":60},"subject":"fix(3p/cppnix): Fix long paths permanently breaking GC","message":"fix(3p/cppnix): Fix long paths permanently breaking GC\n\nSuppose I have a path /nix/store/[hash]-[name]/a/a/a/a/a/[...]/a,\nlong enough that everything after \"/nix/store/\" is longer than 4096\n(MAX_PATH) bytes.\n\nNix will happily allow such a path to be inserted into the store,\nbecause it doesn\u0027t look at all the nested structure.  It just cares\nabout the /nix/store/[hash]-[name] part.  But, when the path is deleted,\nwe encounter a problem.  Nix will move the path to /nix/store/trash, but\nthen when it\u0027s trying to recursively delete the trash directory, it will\nat some point try to unlink\n/nix/store/trash/[hash]-[name]/a/a/a/a/a/[...]/a.  This will fail,\nbecause the path is too long.  After this has failed, any store deletion\noperation will never work again, because Nix needs to delete the trash\ndirectory before recreating it to move new things to it.  (I assume this\nis because otherwise a path being deleted could already exist in the\ntrash, and then moving it would fail.)\n\nThis means that if I can trick somebody into just fetching a tarball\ncontaining a path of the right length, they won\u0027t be able to delete\nstore paths or garbage collect ever again, until the offending path is\nmanually removed from /nix/store/trash.  (And even fixing this manually\nis quite difficult if you don\u0027t understand the issue, because the\nabsolute path that Nix says it failed to remove is also too long for\nrm(1).)\n\nThis patch fixes the issue by making Nix\u0027s recursive delete operation\nuse unlinkat(2).  This function takes a relative path and a directory\nfile descriptor.  We ensure that the relative path is always just the\nname of the directory entry, and therefore its length will never exceed\n255 bytes.  This means that it will never even come close to AX_PATH,\nand Nix will therefore be able to handle removing arbitrarily deep\ndirectory hierachies.\n\nSince the directory file descriptor is used for recursion after being\nused in readDirectory, I made a variant of readDirectory that takes an\nalready open directory stream, to avoid the directory being opened\nmultiple times.  As we have seen from this issue, the less we have to\ninteract with paths, the better, and so it\u0027s good to reuse file\ndescriptors where possible.\n\nI left _deletePath as succeeding even if the parent directory doesn\u0027t\nexist, even though that feels wrong to me, because without that early\nreturn, the linux-sandbox test failed.\n\nReported-by: Alyssa Ross \u003chi@alyssa.is\u003e\nThanks-to: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nTested-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nReviewed-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nChange-Id: Ia5a97f105697786d6207a9b45f4224effb087203\n","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003d9d78db4d9d094f4d93989c4291dcc378b371e291"}],"resolve_conflicts_web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003d9d78db4d9d094f4d93989c4291dcc378b371e291"}]},"parents_data":[{"branch_name":"refs/heads/canon","commit_id":"7a6aa644adb92c224b004867a1846d13c70376c6","is_merged_in_target_branch":false,"change_id":"Ie5273446c4a19403088d0389ae8e3f473af8879a","change_number":13865,"patch_set_number":4,"change_status":"NEW"}],"branch":"refs/heads/canon"},"a36e66049ceb15532353949edfca3e03e010319d":{"kind":"TRIVIAL_REBASE","_number":5,"created":"2025-12-10 22:31:02.000000000","uploader":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"},"ref":"refs/changes/66/13866/5","fetch":{"anonymous http":{"url":"https://cl.tvl.fyi/depot","ref":"refs/changes/66/13866/5","commands":{"Checkout":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/5 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/5 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://cl.tvl.fyi/depot refs/changes/66/13866/5 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://cl.tvl.fyi/depot refs/changes/66/13866/5"}}},"commit":{"parents":[{"commit":"f3b669044f7783df1ff1b9efea0ea74b3e0f7345","subject":"fix(cppnix/libstore): ensure `passAsFile` is created in orig tmpdir","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003df3b669044f7783df1ff1b9efea0ea74b3e0f7345"}]}],"author":{"name":"Alyssa Ross","email":"hi@alyssa.is","date":"2020-04-27 14:15:15.000000000","tz":0},"committer":{"name":"sterni","email":"sternenseemann@systemli.org","date":"2025-12-10 22:28:40.000000000","tz":60},"subject":"fix(3p/cppnix): Fix long paths permanently breaking GC","message":"fix(3p/cppnix): Fix long paths permanently breaking GC\n\nSuppose I have a path /nix/store/[hash]-[name]/a/a/a/a/a/[...]/a,\nlong enough that everything after \"/nix/store/\" is longer than 4096\n(MAX_PATH) bytes.\n\nNix will happily allow such a path to be inserted into the store,\nbecause it doesn\u0027t look at all the nested structure.  It just cares\nabout the /nix/store/[hash]-[name] part.  But, when the path is deleted,\nwe encounter a problem.  Nix will move the path to /nix/store/trash, but\nthen when it\u0027s trying to recursively delete the trash directory, it will\nat some point try to unlink\n/nix/store/trash/[hash]-[name]/a/a/a/a/a/[...]/a.  This will fail,\nbecause the path is too long.  After this has failed, any store deletion\noperation will never work again, because Nix needs to delete the trash\ndirectory before recreating it to move new things to it.  (I assume this\nis because otherwise a path being deleted could already exist in the\ntrash, and then moving it would fail.)\n\nThis means that if I can trick somebody into just fetching a tarball\ncontaining a path of the right length, they won\u0027t be able to delete\nstore paths or garbage collect ever again, until the offending path is\nmanually removed from /nix/store/trash.  (And even fixing this manually\nis quite difficult if you don\u0027t understand the issue, because the\nabsolute path that Nix says it failed to remove is also too long for\nrm(1).)\n\nThis patch fixes the issue by making Nix\u0027s recursive delete operation\nuse unlinkat(2).  This function takes a relative path and a directory\nfile descriptor.  We ensure that the relative path is always just the\nname of the directory entry, and therefore its length will never exceed\n255 bytes.  This means that it will never even come close to AX_PATH,\nand Nix will therefore be able to handle removing arbitrarily deep\ndirectory hierachies.\n\nSince the directory file descriptor is used for recursion after being\nused in readDirectory, I made a variant of readDirectory that takes an\nalready open directory stream, to avoid the directory being opened\nmultiple times.  As we have seen from this issue, the less we have to\ninteract with paths, the better, and so it\u0027s good to reuse file\ndescriptors where possible.\n\nI left _deletePath as succeeding even if the parent directory doesn\u0027t\nexist, even though that feels wrong to me, because without that early\nreturn, the linux-sandbox test failed.\n\nReported-by: Alyssa Ross \u003chi@alyssa.is\u003e\nThanks-to: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nTested-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nReviewed-by: Puck Meerburg \u003cpuck@puckipedia.com\u003e\nChange-Id: Ia5a97f105697786d6207a9b45f4224effb087203\n","web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003da36e66049ceb15532353949edfca3e03e010319d"}],"resolve_conflicts_web_links":[{"name":"cgit","tooltip":"Open in GitWeb","url":"https://code.tvl.fyi/commit/?id\u003da36e66049ceb15532353949edfca3e03e010319d"}]},"parents_data":[{"branch_name":"refs/heads/canon","commit_id":"f3b669044f7783df1ff1b9efea0ea74b3e0f7345","is_merged_in_target_branch":false,"change_id":"Ie5273446c4a19403088d0389ae8e3f473af8879a","change_number":13865,"patch_set_number":5,"change_status":"NEW"}],"branch":"refs/heads/canon"}},"requirements":[{"status":"OK","fallback_text":"Code-Owners","type":"code-owners"}],"submit_records":[{"rule_name":"gerrit~PrologRule","status":"OK","labels":[{"label":"Autosubmit","status":"MAY"},{"label":"Conformant-Commit-Message","status":"OK","applied_by":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"}},{"label":"All-Comments-Resolved","status":"OK","applied_by":{"_account_id":1000034,"name":"sterni","email":"sternenseemann@systemli.org","username":"sterni"}},{"label":"Verified","status":"OK","applied_by":{"_account_id":1000014,"name":"BuildkiteCI","username":"buildkite","tags":["SERVICE_USER"]}},{"label":"Code-Review","status":"OK","applied_by":{"_account_id":1000001,"name":"tazjin","email":"tazjin@tvl.su","username":"tazjin"}}]},{"rule_name":"Code-Owners","status":"OK","requirements":[{"status":"OK","fallback_text":"Code-Owners","type":"code-owners"}]}],"submit_requirements":[{"name":"All-Comments-Resolved","status":"SATISFIED","is_legacy":true,"submittability_expression_result":{"expression":"label:All-Comments-Resolved\u003dgerrit~PrologRule","fulfilled":true,"status":"PASS","passing_atoms":["label:All-Comments-Resolved\u003dgerrit~PrologRule"],"failing_atoms":[]}},{"name":"Verified","status":"SATISFIED","is_legacy":true,"submittability_expression_result":{"expression":"label:Verified\u003dgerrit~PrologRule","fulfilled":true,"status":"PASS","passing_atoms":["label:Verified\u003dgerrit~PrologRule"],"failing_atoms":[]}},{"name":"Code-Owners","status":"SATISFIED","is_legacy":true,"submittability_expression_result":{"expression":"rule:Code-Owners","fulfilled":true,"status":"PASS","passing_atoms":["Code-Owners"],"failing_atoms":[]}},{"name":"Conformant-Commit-Message","status":"SATISFIED","is_legacy":true,"submittability_expression_result":{"expression":"label:Conformant-Commit-Message\u003dgerrit~PrologRule","fulfilled":true,"status":"PASS","passing_atoms":["label:Conformant-Commit-Message\u003dgerrit~PrologRule"],"failing_atoms":[]}},{"name":"Code-Review","status":"SATISFIED","is_legacy":true,"submittability_expression_result":{"expression":"label:Code-Review\u003dgerrit~PrologRule","fulfilled":true,"status":"PASS","passing_atoms":["label:Code-Review\u003dgerrit~PrologRule"],"failing_atoms":[]}}]}
