Opening plaintext names volumes

This commit is contained in:
Matéo Duparc 2021-02-07 14:43:51 +01:00
parent 4d47306b29
commit e63981c788
Signed by: hardcoresushi
GPG Key ID: 007F84120107191E
2 changed files with 442 additions and 398 deletions

View File

@ -15,8 +15,8 @@ android {
applicationId "sushi.hardcore.droidfs" applicationId "sushi.hardcore.droidfs"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 9 versionCode 10
versionName "1.4.1" versionName "1.4.2"
ndk { ndk {
abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a' abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a'
@ -56,11 +56,11 @@ dependencies {
implementation "com.github.bumptech.glide:glide:4.11.0" implementation "com.github.bumptech.glide:glide:4.11.0"
implementation "com.google.android.exoplayer:exoplayer-core:2.11.7" implementation "com.google.android.exoplayer:exoplayer-core:2.11.7"
implementation "com.google.android.exoplayer:exoplayer-ui:2.11.7" implementation "com.google.android.exoplayer:exoplayer-ui:2.11.7"
implementation "androidx.biometric:biometric:1.0.1" implementation "androidx.biometric:biometric:1.1.0"
def camerax_version = "1.0.0-rc01" def camerax_version = "1.1.0-alpha01"
implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:1.0.0-alpha20" implementation "androidx.camera:camera-view:1.0.0-alpha21"
implementation "androidx.camera:camera-extensions:1.0.0-alpha20" implementation "androidx.camera:camera-extensions:1.0.0-alpha21"
} }

View File

@ -2,25 +2,25 @@ package main
import ( import (
"C" "C"
"crypto/cipher"
"crypto/aes"
"syscall"
"strings"
"bytes" "bytes"
"unsafe" "crypto/aes"
"os" "crypto/cipher"
"io"
"fmt" "fmt"
"path/filepath"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"io"
"os"
"path/filepath"
"strings"
"syscall"
"unsafe"
"./gocryptfs_internal/cryptocore" "./gocryptfs_internal/cryptocore"
"./gocryptfs_internal/stupidgcm"
"./gocryptfs_internal/eme" "./gocryptfs_internal/eme"
"./gocryptfs_internal/nametransform" "./gocryptfs_internal/nametransform"
"./rewrites/syscallcompat" "./gocryptfs_internal/stupidgcm"
"./rewrites/configfile" "./rewrites/configfile"
"./rewrites/contentenc" "./rewrites/contentenc"
"./rewrites/syscallcompat"
) )
const ( const (
@ -40,6 +40,7 @@ type File struct {
type SessionVars struct { type SessionVars struct {
root_cipher_dir string root_cipher_dir string
plainTextNames bool
nameTransform *nametransform.NameTransform nameTransform *nametransform.NameTransform
cryptoCore *cryptocore.CryptoCore cryptoCore *cryptocore.CryptoCore
contentEnc *contentenc.ContentEnc contentEnc *contentenc.ContentEnc
@ -72,6 +73,16 @@ func clear_dirCache(sessionID int) {
func openBackingDir(sessionID int, relPath string) (dirfd int, cName string, err error) { func openBackingDir(sessionID int, relPath string) (dirfd int, cName string, err error) {
dirRelPath := nametransform.Dir(relPath) dirRelPath := nametransform.Dir(relPath)
// With PlaintextNames, we don't need to read DirIVs. Easy.
if sessions[sessionID].plainTextNames {
dirfd, err = syscallcompat.OpenDirNofollow(sessions[sessionID].root_cipher_dir, dirRelPath)
if err != nil {
return -1, "", err
}
// If relPath is empty, cName is ".".
cName = filepath.Base(relPath)
return dirfd, cName, nil
}
dir, ok := sessions[sessionID].dirCache[dirRelPath] dir, ok := sessions[sessionID].dirCache[dirRelPath]
if ok { if ok {
// If relPath is empty, cName is ".". // If relPath is empty, cName is ".".
@ -487,6 +498,9 @@ func init_new_session(root_cipher_dir string, masterkey []byte, cf *configfile.C
} }
if err == nil { if err == nil {
var new_session SessionVars var new_session SessionVars
new_session.plainTextNames = cf.IsFeatureFlagSet(configfile.FlagPlaintextNames)
emeCipher = eme.New(emeBlockCipher) emeCipher = eme.New(emeBlockCipher)
new_session.nameTransform = nametransform.New(emeCipher, true, true) new_session.nameTransform = nametransform.New(emeCipher, true, true)
@ -524,7 +538,7 @@ func init_new_session(root_cipher_dir string, masterkey []byte, cf *configfile.C
if sessions == nil { if sessions == nil {
sessions = make(map[int]SessionVars) sessions = make(map[int]SessionVars)
} }
sessions[sessionID] = new_session; sessions[sessionID] = new_session
return sessionID return sessionID
} }
return -1 return -1
@ -614,11 +628,13 @@ func gcf_list_dir(sessionID int, dirName string) (*C.char, *C.int, C.int) {
} }
// Get DirIV (stays nil if PlaintextNames is used) // Get DirIV (stays nil if PlaintextNames is used)
var cachedIV []byte var cachedIV []byte
if !sessions[sessionID].plainTextNames {
// Read the DirIV from disk // Read the DirIV from disk
cachedIV, err = nametransform.ReadDirIVAt(fd) cachedIV, err = nametransform.ReadDirIVAt(fd)
if err != nil { if err != nil {
return nil, nil, 0 return nil, nil, 0
} }
}
// Decrypted directory entries // Decrypted directory entries
var plain strings.Builder var plain strings.Builder
var modes []uint32 var modes []uint32
@ -629,6 +645,11 @@ func gcf_list_dir(sessionID int, dirName string) (*C.char, *C.int, C.int) {
// silently ignore "gocryptfs.conf" in the top level dir // silently ignore "gocryptfs.conf" in the top level dir
continue continue
} }
if sessions[sessionID].plainTextNames {
plain.WriteString(cipherEntries[i].Name + "\x00")
modes = append(modes, cipherEntries[i].Mode)
continue
}
if cName == nametransform.DirIVFilename { if cName == nametransform.DirIVFilename {
// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled // silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled
continue continue
@ -670,6 +691,18 @@ func gcf_mkdir(sessionID int, newPath string) bool {
return false return false
} }
defer syscall.Close(dirfd) defer syscall.Close(dirfd)
if sessions[sessionID].plainTextNames {
err = syscallcompat.Mkdirat(dirfd, cName, folder_mode)
if err != nil {
return false
}
var ust unix.Stat_t
err = syscallcompat.Fstatat(dirfd, cName, &ust, unix.AT_SYMLINK_NOFOLLOW)
if err != nil {
return false
}
} else {
// We need write and execute permissions to create gocryptfs.diriv. // We need write and execute permissions to create gocryptfs.diriv.
// Also, we need read permissions to open the directory (to avoid // Also, we need read permissions to open the directory (to avoid
// race-conditions between getting and setting the mode). // race-conditions between getting and setting the mode).
@ -718,6 +751,7 @@ func gcf_mkdir(sessionID int, newPath string) bool {
return false return false
} }
} }
}
return true return true
} }
@ -729,6 +763,11 @@ func gcf_rmdir(sessionID int, relPath string) bool {
return false return false
} }
defer syscall.Close(parentDirFd) defer syscall.Close(parentDirFd)
if sessions[sessionID].plainTextNames {
// Unlinkat with AT_REMOVEDIR is equivalent to Rmdir
err = unix.Unlinkat(parentDirFd, cName, unix.AT_REMOVEDIR)
return err_to_bool(err)
}
dirfd, err := syscallcompat.Openat(parentDirFd, cName, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) dirfd, err := syscallcompat.Openat(parentDirFd, cName, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
if err != nil { if err != nil {
return false return false
@ -797,7 +836,7 @@ func gcf_open_write_mode(sessionID int, path string) int {
defer syscall.Close(dirfd) defer syscall.Close(dirfd)
fd := -1 fd := -1
// Handle long file name // Handle long file name
if nametransform.IsLongContent(cName) { if !sessions[sessionID].plainTextNames && nametransform.IsLongContent(cName) {
// Create ".name" // Create ".name"
err = sessions[sessionID].nameTransform.WriteLongNameAt(dirfd, cName, path) err = sessions[sessionID].nameTransform.WriteLongNameAt(dirfd, cName, path)
if err != nil { if err != nil {
@ -851,7 +890,7 @@ func gcf_close_file(sessionID, handleID int){
func gcf_read_file(sessionID, handleID int, offset uint64, dst_buff []byte) uint32 { func gcf_read_file(sessionID, handleID int, offset uint64, dst_buff []byte) uint32 {
length := uint64(len(dst_buff)) length := uint64(len(dst_buff))
if length > contentenc.MAX_KERNEL_WRITE { if length > contentenc.MAX_KERNEL_WRITE {
return 0; return 0
} }
out, _ := doRead(sessionID, handleID, dst_buff[:0], offset, length) out, _ := doRead(sessionID, handleID, dst_buff[:0], offset, length)
@ -863,7 +902,7 @@ func gcf_read_file(sessionID, handleID int, offset uint64, dst_buff []byte) uint
func gcf_write_file(sessionID, handleID int, offset uint64, data []byte) uint32 { func gcf_write_file(sessionID, handleID int, offset uint64, data []byte) uint32 {
length := uint64(len(data)) length := uint64(len(data))
if length > contentenc.MAX_KERNEL_WRITE { if length > contentenc.MAX_KERNEL_WRITE {
return 0; return 0
} }
written, _ := doWrite(sessionID, handleID, data, offset) written, _ := doWrite(sessionID, handleID, data, offset)
@ -899,6 +938,11 @@ func gcf_rename(sessionID int, oldPath string, newPath string) bool {
return false return false
} }
defer syscall.Close(newDirfd) defer syscall.Close(newDirfd)
// Easy case.
if sessions[sessionID].plainTextNames {
return err_to_bool(syscallcompat.Renameat(oldDirfd, oldCName, newDirfd, newCName))
}
// Long destination file name: create .name file // Long destination file name: create .name file
nameFileAlreadyThere := false nameFileAlreadyThere := false
if nametransform.IsLongContent(newCName) { if nametransform.IsLongContent(newCName) {
@ -950,7 +994,7 @@ func gcf_remove_file(sessionID int, path string) bool {
return false return false
} }
// Delete ".name" file // Delete ".name" file
if nametransform.IsLongContent(cName) { if !sessions[sessionID].plainTextNames && nametransform.IsLongContent(cName) {
err = nametransform.DeleteLongNameAt(dirfd, cName) err = nametransform.DeleteLongNameAt(dirfd, cName)
} }
return err_to_bool(err) return err_to_bool(err)