android: prevent imported archive from being written outside the export folder

This commit is contained in:
spaced4ndy
2026-08-14 17:24:28 +04:00
parent 6fcfbd54c5
commit 89d88621f2
3 changed files with 8 additions and 2 deletions
@@ -233,7 +233,8 @@ actual fun getFileName(uri: URI): String? {
val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
cursor.moveToFirst()
// Can make an exception
cursor.getString(nameIndex)
// the provider controls this value, and callers use it as a bare file name
cursor.getString(nameIndex)?.let { File(it).name }
}
} catch (e: Exception) {
null
@@ -753,6 +753,11 @@ private fun saveArchiveFromURI(importedArchiveURI: URI): String? {
if (inputStream != null && archiveName != null) {
val archivePath = "$databaseExportDir${File.separator}$archiveName"
val destFile = File(archivePath)
// resolves symlinks, so it also catches a final component linking outside the folder
if (destFile.canonicalFile.parentFile != databaseExportDir.canonicalFile) {
Log.e(TAG, "saveArchiveFromURI path outside of export folder")
return null
}
Files.copy(inputStream, destFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
archivePath
} else {
+1 -1
View File
@@ -345,7 +345,7 @@ class ArchiveConfig(
### Import Flow
1. User selects an archive file.
2. UI copies it to a temp location and constructs an `ArchiveConfig`.
2. UI copies it into `databaseExportDir` and constructs an `ArchiveConfig`. The destination is confined to that folder: `getFileName` returns a bare file name on every platform, and `saveArchiveFromURI` checks the canonical destination before copying.
3. Calls `apiImportArchive(config)` which sends `CC.ApiImportArchive` to the Haskell core.
4. The core extracts and replaces both databases.
5. Returns `CR.ArchiveImported` with a list of `ArchiveError` (non-fatal issues during import).