attempt to prevent shell escape
This commit is contained in:
@@ -205,9 +205,10 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if (!directory.exists()) {
|
||||
RootManager.executeCommand("mkdir -p \"$currentPath\"")
|
||||
val safePath = RootManager.shellEscape(currentPath)
|
||||
RootManager.executeCommand("mkdir -p $safePath")
|
||||
// Create marker file to indicate this folder was created by the app
|
||||
RootManager.executeCommand("touch \"$currentPath/.isodroiddir\"")
|
||||
RootManager.executeCommand("touch $safePath/.isodroiddir")
|
||||
}
|
||||
|
||||
// Try multiple methods to list files
|
||||
@@ -220,8 +221,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private suspend fun loadFilesViaFind(currentPath: String): List<IsoFile>? {
|
||||
// Use find command - more reliable for getting full paths
|
||||
val safePath = RootManager.shellEscape(currentPath)
|
||||
val result = RootManager.executeCommand(
|
||||
"find \"$currentPath\" -maxdepth 1 -type f \\( -iname '*.iso' -o -iname '*.img' \\) 2>/dev/null"
|
||||
"find $safePath -maxdepth 1 -type f \\( -iname '*.iso' -o -iname '*.img' \\) 2>/dev/null"
|
||||
)
|
||||
|
||||
if (!result.success || result.output.isBlank()) return null
|
||||
@@ -231,8 +233,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
.mapNotNull { filePath ->
|
||||
val file = File(filePath.trim())
|
||||
val name = file.name
|
||||
// Get file size via stat
|
||||
val sizeResult = RootManager.executeCommand("stat -c %s \"$filePath\" 2>/dev/null")
|
||||
// Get file size via stat with safe escaping
|
||||
val safeFilePath = RootManager.shellEscape(filePath.trim())
|
||||
val sizeResult = RootManager.executeCommand("stat -c %s $safeFilePath 2>/dev/null")
|
||||
val size = sizeResult.output.trim().toLongOrNull() ?: 0L
|
||||
IsoFile(
|
||||
path = filePath.trim(),
|
||||
@@ -246,8 +249,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private suspend fun loadFilesViaLs(currentPath: String): List<IsoFile>? {
|
||||
// Simple ls command - just get filenames
|
||||
val safePath = RootManager.shellEscape(currentPath)
|
||||
val result = RootManager.executeCommand(
|
||||
"ls \"$currentPath\" 2>/dev/null"
|
||||
"ls $safePath 2>/dev/null"
|
||||
)
|
||||
|
||||
if (!result.success || result.output.isBlank()) return null
|
||||
@@ -259,8 +263,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
}
|
||||
.mapNotNull { name ->
|
||||
val filePath = "$currentPath/$name"
|
||||
// Get file size via stat
|
||||
val sizeResult = RootManager.executeCommand("stat -c %s \"$filePath\" 2>/dev/null")
|
||||
// Get file size via stat with safe escaping
|
||||
val safeFilePath = RootManager.shellEscape(filePath)
|
||||
val sizeResult = RootManager.executeCommand("stat -c %s $safeFilePath 2>/dev/null")
|
||||
val size = sizeResult.output.trim().toLongOrNull() ?: 0L
|
||||
IsoFile(
|
||||
path = filePath,
|
||||
@@ -444,13 +449,14 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val blockSize = 1024 * 1024L // 1MB blocks
|
||||
val totalBlocks = totalBytes / blockSize
|
||||
var writtenBlocks = 0L
|
||||
val safeFilePath = RootManager.shellEscape(filePath)
|
||||
|
||||
// Create file with dd in background, checking for cancellation
|
||||
val result = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
|
||||
try {
|
||||
// First, create the file with truncate to reserve space indication
|
||||
val createResult = RootManager.executeCommand(
|
||||
"dd if=/dev/zero of=\"$filePath\" bs=1M count=0 seek=$totalBlocks 2>/dev/null"
|
||||
"dd if=/dev/zero of=$safeFilePath bs=1M count=0 seek=$totalBlocks 2>/dev/null"
|
||||
)
|
||||
|
||||
if (!createResult.success) {
|
||||
@@ -461,18 +467,18 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
while (writtenBlocks < totalBlocks) {
|
||||
if (CreateImgEventBus.isCancelRequested()) {
|
||||
// Clean up partial file
|
||||
RootManager.executeCommand("rm -f \"$filePath\"")
|
||||
RootManager.executeCommand("rm -f $safeFilePath")
|
||||
return@withContext false
|
||||
}
|
||||
|
||||
// Write a chunk (up to 64MB at a time for efficiency)
|
||||
val chunksToWrite = minOf(64, totalBlocks - writtenBlocks)
|
||||
val chunkResult = RootManager.executeCommand(
|
||||
"dd if=/dev/zero of=\"$filePath\" bs=1M count=$chunksToWrite seek=$writtenBlocks conv=notrunc 2>/dev/null"
|
||||
"dd if=/dev/zero of=$safeFilePath bs=1M count=$chunksToWrite seek=$writtenBlocks conv=notrunc 2>/dev/null"
|
||||
)
|
||||
|
||||
if (!chunkResult.success) {
|
||||
RootManager.executeCommand("rm -f \"$filePath\"")
|
||||
RootManager.executeCommand("rm -f $safeFilePath")
|
||||
return@withContext false
|
||||
}
|
||||
|
||||
@@ -484,7 +490,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
RootManager.executeCommand("rm -f \"$filePath\"")
|
||||
RootManager.executeCommand("rm -f $safeFilePath")
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -508,14 +514,18 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val oldPath = file.path
|
||||
val newPath = "${oldPath.substringBeforeLast("/")}/$newName"
|
||||
|
||||
// Use shell-safe escaping to prevent command injection
|
||||
val safeOldPath = RootManager.shellEscape(oldPath)
|
||||
val safeNewPath = RootManager.shellEscape(newPath)
|
||||
|
||||
// Check if new file already exists
|
||||
val checkResult = RootManager.executeCommand("test -f \"$newPath\" && echo exists")
|
||||
val checkResult = RootManager.executeCommand("test -f $safeNewPath && echo exists")
|
||||
if (checkResult.output.trim() == "exists") {
|
||||
_uiState.update { it.copy(errorMessage = "File already exists: $newName") }
|
||||
return@launch
|
||||
}
|
||||
|
||||
val result = RootManager.executeCommand("mv \"$oldPath\" \"$newPath\"")
|
||||
val result = RootManager.executeCommand("mv $safeOldPath $safeNewPath")
|
||||
if (result.success) {
|
||||
_uiState.update { it.copy(successMessage = "Renamed to $newName") }
|
||||
loadFiles()
|
||||
@@ -527,7 +537,8 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
fun deleteFile(file: IsoFile) {
|
||||
viewModelScope.launch {
|
||||
val result = RootManager.executeCommand("rm -f \"${file.path}\"")
|
||||
val safePath = RootManager.shellEscape(file.path)
|
||||
val result = RootManager.executeCommand("rm -f $safePath")
|
||||
if (result.success) {
|
||||
_uiState.update { it.copy(successMessage = "Deleted ${file.name}") }
|
||||
loadFiles()
|
||||
|
||||
Reference in New Issue
Block a user