Repository navigation
Commit dcda33c
ADFA-5005: Fix SDK bootstrap crash extracting android-sdk.zip (#1621)
* ADFA-5005: Fix SDK bootstrap crash extracting android-sdk.zip
The bundled android-sdk.zip.br has no directory entries, so its very
first zip entry (build-tools/35.0.0/NOTICE.txt) failed to extract on
every fresh install: extractZipToDir only created parent directories
for entries explicitly flagged as directories, never for plain file
entries, and ANDROID_HOME is wiped before each install.
Create the parent directory unconditionally before writing each file
entry. Verified end-to-end on-device: OOBE completes and
build-tools/35.0.0/NOTICE.txt lands at the expected 1,068,025 bytes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* ADFA-5005: Add regression test for extractZipToDir missing parent dirs
Builds an in-memory zip with a single nested file entry and no
directory entries, matching how android-sdk.zip is packaged, and
asserts extraction creates the parent directories and preserves the
file content. Confirmed the test fails with NoSuchFileException
against the pre-fix code and passes with the fix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* ADFA-5005: Harden extractZipToDir against on-disk symlink escapes
The existing normalize()/startsWith() checks validate the zip entry
name lexically, but not the actual filesystem state -- a symlink
already present under destDir (e.g. from a merged/reused install dir
in SplitAssetsInstaller) could redirect Files.createDirectories() or
Files.newOutputStream() outside destDir undetected.
Resolve destFile's real parent path after creating it and re-check
containment against destDir's real path, and refuse to write through
a destFile that already exists as a symlink. Added regression tests
for both vectors; confirmed they fail without this change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* ADFA-5005: Close symlink-escape gap in extractZipToDir directory entries
Review of PR #1621 flagged an asymmetry: the on-disk symlink checks
added for file entries didn't cover directory entries, so
Files.createDirectories(destFile) would silently no-op through a
pre-existing symlink pointing outside destDir (or, if the symlink
target didn't exist, create directories at the symlink's target
outside destDir).
Hoist the existing-symlink check above the isDirectory branch so it
applies to both, and add the same real-path containment check after
creating a directory entry. Added a regression test confirming a bare
directory entry resolving to an escaping symlink is now rejected;
confirmed it fails without this change and passes with it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* ADFA-5005: Cache last-verified parent to cut redundant toRealPath() calls
Review of PR #1621 noted that destFile.parent.toRealPath() runs once
per file entry even though zip entries are commonly clustered by
directory (e.g. 20 files under build-tools/35.0.0/ alone) -- each
consecutive sibling re-walks and re-resolves the same parent path.
Cache the last-verified parent and skip the real-path containment
check when the current entry's parent is unchanged. Nothing in the
loop can turn an already-verified real directory into a symlink
mid-run, so caching by lexical parent equality doesn't weaken the
check. Added a test exercising multiple sibling files under one
directory (the only test that hit the cache-hit branch); full assets
test suite still green.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* ADFA-5005: Address review feedback on symlink hardening
- Route SplitAssetsInstaller/BundledAssetsInstaller's plugin-zip
extraction through the hardened extractZipToDir() instead of a
lexical-only reimplementation, so all three extraction sites share
one symlink-hardened path.
- Add a regression test covering a file entry under a pre-existing
symlinked parent with no directory entry -- the shape android-sdk.zip
actually has, and the only path that previously exercised the
toRealPath() escape check.
- Fix a stale comment in ExtractZipToDirMergeTest's zipOf helper that
no longer matched extractZipToDir's behavior.
- Stop leaking temp dirs across the symlink tests, using a walker that
won't follow symlinks into deletion.
* ADFA-5005: Fix symlink-escape test to actually reach the toRealPath() guard
hal-eisen-adfa found that the previous test (`linked/nested.txt`, one level
below the symlink) made destFile.parent the symlink itself, so
Files.createDirectories() threw FileAlreadyExistsException under
NOFOLLOW_LINKS before the toRealPath() guard ever ran -- the test failed,
and the guard stayed uncovered.
Use a two-level entry (`linked/sub/nested.txt`) instead, per his repro:
createDirectories() silently traverses the symlink to create `sub` for real
inside the escape target, and only then does the toRealPath() check on
destFile.parent fire and reject it. That's the guard this test is meant to
cover.
Also switch the test's cleanup to deleteRecursivelyWithoutFollowingLinks()
(copied from ExtractZipToDirMergeTest), since the prior deleteRecursively()
follows symlinks and would delete the escape target's contents if outsideDir
happened to be cleaned up after destDir.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>1 parent e429548 commit dcda33c
5 files changed
Lines changed: 272 additions & 63 deletions
File tree
- app/src
- main/java/com/itsaky/androidide/assets
- test/java/com/itsaky/androidide/assets
Lines changed: 27 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
245 | 245 | | |
246 | 246 | | |
247 | 247 | | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
248 | 256 | | |
249 | 257 | | |
250 | 258 | | |
| |||
260 | 268 | | |
261 | 269 | | |
262 | 270 | | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
263 | 279 | | |
264 | 280 | | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
265 | 284 | | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
266 | 293 | | |
267 | 294 | | |
268 | 295 | | |
| |||
Lines changed: 1 addition & 22 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
33 | 32 | | |
34 | 33 | | |
35 | 34 | | |
| |||
174 | 173 | | |
175 | 174 | | |
176 | 175 | | |
177 | | - | |
178 | | - | |
179 | | - | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | | - | |
196 | | - | |
197 | | - | |
| 176 | + | |
198 | 177 | | |
199 | 178 | | |
200 | 179 | | |
| |||
Lines changed: 1 addition & 22 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
27 | 26 | | |
28 | 27 | | |
29 | 28 | | |
| |||
167 | 166 | | |
168 | 167 | | |
169 | 168 | | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
177 | | - | |
178 | | - | |
179 | | - | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
| 169 | + | |
191 | 170 | | |
192 | 171 | | |
193 | 172 | | |
| |||
Lines changed: 102 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
| 12 | + | |
11 | 13 | | |
12 | 14 | | |
13 | 15 | | |
| 16 | + | |
| 17 | + | |
14 | 18 | | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
15 | 27 | | |
16 | 28 | | |
17 | 29 | | |
| |||
48 | 60 | | |
49 | 61 | | |
50 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
51 | 153 | | |
0 commit comments