Skip to content

Commit 0f05b7e

Browse files
itsXuStdeepin-bot[bot]
authored andcommitted
fix: [249587/decrypt] re-decrypt after interrupted.
when interrupted at fs recovery phase, e2image cannot recovery from broken status. move filesystem manully. Log: fix issue Bug: https://pms.uniontech.com/bug-view-249587.html
1 parent 7731c4d commit 0f05b7e

3 files changed

Lines changed: 272 additions & 59 deletions

File tree

src/dde-file-manager-daemon/daemonplugin-file-encrypt/encrypt/diskencrypt.cpp

Lines changed: 254 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <unistd.h>
2424
#include <fcntl.h>
2525
#include <functional>
26+
#include <stdio.h>
2627

2728
FILE_ENCRYPT_USE_NS
2829
using namespace disk_encrypt;
@@ -355,72 +356,27 @@ int disk_encrypt_funcs::bcDecryptDevice(const QString &device,
355356
const QString &passphrase)
356357
{
357358
// backup header first
358-
QString headerPath;
359-
uint32_t flags;
360-
struct crypt_device *cdev = nullptr;
361359
dfmbase::FinallyUtil finalClear([&] {
362-
if (cdev) crypt_free(cdev);
363360
gCurrDecryptintDevice.clear();
364361
});
365362
gCurrDecryptintDevice = device;
366363

364+
QString headerPath;
367365
int ret = bcBackupCryptHeader(device, headerPath);
368366
CHECK_INT(ret, "backup header failed " + device, -kErrorBackupHeader);
369367

370-
ret = crypt_init_data_device(&cdev,
371-
headerPath.toStdString().c_str(),
372-
device.toStdString().c_str());
373-
CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
374-
375-
ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
376-
CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
377-
378-
ret = crypt_persistent_flags_get(cdev,
379-
CRYPT_FLAGS_REQUIREMENTS,
380-
&flags);
381-
CHECK_INT(ret, "get device flag failed " + device, -kErrorGetReencryptFlag);
382-
bool underEncrypting = (flags & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT) || (flags & CRYPT_REQUIREMENT_ONLINE_REENCRYPT);
383-
384-
crypt_params_reencrypt param;
385-
ret = crypt_reencrypt_status(cdev, &param);
386-
CHECK_INT(ret, "check reencrypt status failed" + device, -kErrorCheckReencryptStatus);
387-
388-
underEncrypting &= (param.mode == CRYPT_REENCRYPT_ENCRYPT);
389-
CHECK_BOOL(!underEncrypting,
390-
"device is under encrypting... " + device + " the flags are: " + QString::number(flags),
391-
-kErrorWrongFlags);
392-
393-
if (ret == CRYPT_REENCRYPT_CRASH) { // repair is needed.
394-
QString dmName = "dm-" + device.mid(5);
395-
ret = crypt_activate_by_passphrase(cdev, dmName.toStdString().c_str(),
396-
CRYPT_ANY_SLOT,
397-
passphrase.toStdString().c_str(),
398-
passphrase.length(),
399-
CRYPT_ACTIVATE_RECOVERY);
400-
CHECK_INT(ret, "open device failed " + device, -kErrorActive);
401-
402-
// close device avoid operating.
403-
ret = crypt_deactivate(cdev, dmName.toStdString().c_str());
368+
int status = bcReadHeader(headerPath);
369+
if (status != kDecryptFully) {
370+
ret = bcDoDecryptDevice(device, passphrase, headerPath);
371+
CHECK_INT(ret, "decrypt failed " + device, -kErrorDecryptFailed);
404372
}
405373

406-
ret = crypt_reencrypt_init_by_passphrase(cdev,
407-
nullptr,
408-
passphrase.toStdString().c_str(),
409-
passphrase.length(),
410-
CRYPT_ANY_SLOT,
411-
CRYPT_ANY_SLOT,
412-
nullptr,
413-
nullptr,
414-
decryptParams());
415-
CHECK_INT(ret, "init reencrypt failed " + device, -kErrorWrongPassphrase);
416-
417-
ret = crypt_reencrypt(cdev, bcDecryptProgress);
418-
CHECK_INT(ret, "decrypt failed" + device, -kErrorReencryptFailed);
419-
420-
bool res = fs_resize::recoverySuperblock_ext(device, headerPath);
374+
bool res = block_device_utils::bcMoveFsForward(device);
421375
CHECK_BOOL(res, "recovery fs failed " + device, -kErrorResizeFs);
422376

423-
if (!headerPath.isEmpty()) ::remove(headerPath.toStdString().c_str());
377+
if (!headerPath.isEmpty())
378+
::remove(headerPath.toStdString().c_str());
379+
424380
return 0;
425381
}
426382

@@ -916,3 +872,247 @@ bool disk_encrypt_utils::bcHasEncryptConfig(const QString &dev)
916872
const QString &devPath = obj.value("device-path").toString();
917873
return devPath == dev;
918874
}
875+
876+
quint64 block_device_utils::bcGetBlockSize(const QString &device)
877+
{
878+
auto dev = bcCreateBlkDev(device);
879+
if (!dev)
880+
return 0;
881+
return dev->getProperty(dfmmount::Property::kPartitionSize).toULongLong();
882+
}
883+
884+
bool block_device_utils::bcMoveFsForward(const QString &device)
885+
{
886+
static const quint64 kStepSize = 16 * 1024 * 1024; // luks header size.
887+
888+
QString dev(device);
889+
QString logFilePath("/boot/usec-crypt/dfm_mv_fs_" + dev.replace("/", "_"));
890+
891+
QFile logFile(logFilePath);
892+
QFile blockFile(device);
893+
char *buf = new char[kStepSize];
894+
895+
auto clearMem = [&] {
896+
if (logFile.isOpen())
897+
logFile.close();
898+
if (blockFile.isOpen())
899+
blockFile.close();
900+
delete[] buf;
901+
};
902+
903+
if (!logFile.exists()) {
904+
if (!logFile.open(QIODevice::Truncate | QIODevice::ReadWrite)) {
905+
qWarning() << "cannot create log file!" << logFilePath;
906+
clearMem();
907+
return false;
908+
}
909+
logFile.close();
910+
}
911+
if (!logFile.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
912+
qWarning() << "cannot open log file!" << logFilePath;
913+
clearMem();
914+
return false;
915+
}
916+
917+
if (!blockFile.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
918+
qWarning() << "cannot open device!" << device;
919+
clearMem();
920+
return false;
921+
}
922+
923+
// calc total move counts.
924+
quint64 partSize = block_device_utils::bcGetBlockSize(device);
925+
if (partSize == 0) {
926+
qWarning() << "get block size failed!";
927+
clearMem();
928+
return false;
929+
}
930+
quint64 mvCount = partSize / kStepSize;
931+
if (partSize % kStepSize) mvCount += 1;
932+
933+
// read break point.
934+
auto records = logFile.readAll().split(',');
935+
quint64 lastMovedIndex = (records.count() > 0) ? records.last().toULongLong() : 0;
936+
937+
// start move segments
938+
disk_encrypt_funcs::bcDecryptProgress(100, 99, nullptr);
939+
qApp->processEvents();
940+
941+
quint64 currMovedIndex = lastMovedIndex + 1;
942+
for (; currMovedIndex <= mvCount; ++currMovedIndex, ++lastMovedIndex) {
943+
// qInfo() << "moving..." << currMovedIndex << device;
944+
// seek current move position
945+
if (!blockFile.seek(currMovedIndex * kStepSize)) {
946+
qWarning() << "seek pos failed!" << currMovedIndex * kStepSize;
947+
clearMem();
948+
return false;
949+
}
950+
951+
// read next step
952+
memset(buf, 0, kStepSize);
953+
quint64 readed = blockFile.read(buf, kStepSize);
954+
955+
// write to previous step position.
956+
if (!blockFile.seek((lastMovedIndex)*kStepSize)) {
957+
qWarning() << "seek target failed!" << lastMovedIndex * kStepSize;
958+
clearMem();
959+
return false;
960+
}
961+
quint64 wrote = blockFile.write(buf, readed);
962+
if (wrote != readed) {
963+
qWarning() << "read write size not match!";
964+
clearMem();
965+
return false;
966+
}
967+
if (!blockFile.flush() || fsync(blockFile.handle()) != 0) {
968+
qWarning() << "cannot flush device file!" << device;
969+
clearMem();
970+
return false;
971+
}
972+
973+
// recore current index.
974+
QString pos = "," + QString::number(currMovedIndex);
975+
logFile.write(pos.toLocal8Bit());
976+
if (!logFile.flush() || fsync(logFile.handle()) != 0) {
977+
qWarning() << "cannot flush log file!" << logFilePath;
978+
clearMem();
979+
return false;
980+
}
981+
// qInfo() << "moved..." << currMovedIndex << device;
982+
}
983+
984+
clearMem();
985+
986+
// remove log file on success.
987+
::remove(logFilePath.toStdString().c_str());
988+
989+
// update udev on move finished.
990+
::system("udevadm trigger");
991+
992+
return true;
993+
}
994+
995+
int disk_encrypt_funcs::bcDoDecryptDevice(const QString &device, const QString &passphrase, const QString &headerPath)
996+
{
997+
struct crypt_device *cdev = nullptr;
998+
dfmbase::FinallyUtil finalClear([&] {
999+
if (cdev) crypt_free(cdev);
1000+
});
1001+
1002+
int ret = crypt_init_data_device(&cdev,
1003+
headerPath.toStdString().c_str(),
1004+
device.toStdString().c_str());
1005+
CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
1006+
1007+
ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
1008+
CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
1009+
1010+
uint32_t flags;
1011+
ret = crypt_persistent_flags_get(cdev,
1012+
CRYPT_FLAGS_REQUIREMENTS,
1013+
&flags);
1014+
CHECK_INT(ret, "get device flag failed " + device, -kErrorGetReencryptFlag);
1015+
bool underEncrypting = (flags & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT) || (flags & CRYPT_REQUIREMENT_ONLINE_REENCRYPT);
1016+
1017+
crypt_params_reencrypt param;
1018+
ret = crypt_reencrypt_status(cdev, &param);
1019+
CHECK_INT(ret, "check reencrypt status failed" + device, -kErrorCheckReencryptStatus);
1020+
1021+
underEncrypting &= (param.mode == CRYPT_REENCRYPT_ENCRYPT);
1022+
CHECK_BOOL(!underEncrypting,
1023+
"device is under encrypting... " + device + " the flags are: " + QString::number(flags),
1024+
-kErrorWrongFlags);
1025+
1026+
if (ret == CRYPT_REENCRYPT_CRASH) { // repair is needed.
1027+
QString dmName = "dm-" + device.mid(5);
1028+
ret = crypt_activate_by_passphrase(cdev, dmName.toStdString().c_str(),
1029+
CRYPT_ANY_SLOT,
1030+
passphrase.toStdString().c_str(),
1031+
passphrase.length(),
1032+
CRYPT_ACTIVATE_RECOVERY);
1033+
CHECK_INT(ret, "open device failed " + device, -kErrorActive);
1034+
1035+
// close device avoid operating.
1036+
ret = crypt_deactivate(cdev, dmName.toStdString().c_str());
1037+
}
1038+
1039+
// if fully decrypted
1040+
1041+
ret = crypt_reencrypt_init_by_passphrase(cdev,
1042+
nullptr,
1043+
passphrase.toStdString().c_str(),
1044+
passphrase.length(),
1045+
CRYPT_ANY_SLOT,
1046+
CRYPT_ANY_SLOT,
1047+
nullptr,
1048+
nullptr,
1049+
decryptParams());
1050+
CHECK_INT(ret, "init reencrypt failed " + device, -kErrorWrongPassphrase);
1051+
1052+
ret = crypt_reencrypt(cdev, bcDecryptProgress);
1053+
CHECK_INT(ret, "decrypt failed" + device, -kErrorReencryptFailed);
1054+
1055+
return kSuccess;
1056+
}
1057+
1058+
int disk_encrypt_funcs::bcReadHeader(const QString &header)
1059+
{
1060+
QFile headerFile(header);
1061+
if (!headerFile.open(QIODevice::ReadOnly)) {
1062+
qWarning() << "open header failed!";
1063+
return kInvalidHeader;
1064+
}
1065+
1066+
headerFile.seek(4096); // header json starts at 4096
1067+
QString jsonStr = headerFile.readLine();
1068+
headerFile.close();
1069+
1070+
QJsonDocument doc = QJsonDocument::fromJson(jsonStr.toLocal8Bit());
1071+
auto obj = doc.object();
1072+
1073+
// read segments
1074+
auto segments = obj.value("segments").toObject();
1075+
if (segments.isEmpty()) {
1076+
qWarning() << "segments not found";
1077+
return kInvalidHeader;
1078+
}
1079+
bool hasLinear = false, hasCrypt = false;
1080+
for (auto iter = segments.begin(); iter != segments.end(); ++iter) {
1081+
auto segment = iter.value().toObject();
1082+
auto type = segment.value("type").toString();
1083+
if (type == "linear")
1084+
hasLinear = true;
1085+
if (type == "crypt")
1086+
hasCrypt = true;
1087+
}
1088+
1089+
// read mode
1090+
QString mode;
1091+
auto keyslots = obj.value("keyslots").toObject();
1092+
for (auto iter = keyslots.begin(); iter != keyslots.end(); ++iter) {
1093+
auto keyslot = iter.value().toObject();
1094+
if (keyslot.value("type").toString() == "reencrypt") {
1095+
mode = keyslot.value("mode").toString();
1096+
break;
1097+
}
1098+
}
1099+
1100+
if (mode == "encrypt") {
1101+
if (hasLinear && hasCrypt)
1102+
return kEncryptInProgress;
1103+
if (hasLinear)
1104+
return kEncryptInit;
1105+
} else if (mode == "decrypt") {
1106+
if (hasLinear && hasCrypt)
1107+
return kDecryptInProgress;
1108+
if (hasCrypt)
1109+
return kDecryptInit;
1110+
} else {
1111+
if (hasLinear && !hasCrypt)
1112+
return kDecryptFully;
1113+
if (!hasLinear && hasCrypt)
1114+
return kEncryptFully;
1115+
}
1116+
1117+
return kInvalidHeader;
1118+
}

src/dde-file-manager-daemon/daemonplugin-file-encrypt/encrypt/diskencrypt.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ enum EncryptVersion {
2525
kVersionUnknown = 10000,
2626
}; // enum EncryptVersion
2727

28+
enum HeaderStatus {
29+
kInvalidHeader = -1,
30+
kEncryptInit,
31+
kEncryptInProgress,
32+
kEncryptFully,
33+
kDecryptInit,
34+
kDecryptInProgress,
35+
kDecryptFully,
36+
};
37+
2838
namespace disk_encrypt_funcs {
2939
int bcInitHeaderFile(const EncryptParams &params, QString &headerPath, int *keyslotCipher, int *keyslotRecKey);
3040
int bcGetToken(const QString &device, QString *tokenJson);
@@ -34,12 +44,13 @@ int bcResumeReencrypt(const QString &device, const QString &passphrase, const QS
3444
int bcChangePassphrase(const QString &device, const QString &oldPassphrase, const QString &newPassphrase, int *keyslot);
3545
int bcChangePassphraseByRecKey(const QString &device, const QString &oldPassphrase, const QString &newPassphrase, int *keyslot);
3646
int bcDecryptDevice(const QString &device, const QString &passphrase);
47+
int bcDoDecryptDevice(const QString &device, const QString &passphrase, const QString &headerPath);
3748
int bcBackupCryptHeader(const QString &device, QString &headerPath);
3849
int bcDoSetupHeader(const EncryptParams &params, QString *headerPath, int *keyslotCipher, int *keyslotRecKey);
3950
int bcPrepareHeaderFile(const QString &device, QString *headerPath);
4051
int bcSetLabel(const QString &device, const QString &label);
4152
int bcOpenDevice(const QString &device, const QString &activeName);
42-
53+
int bcReadHeader(const QString &header);
4354
int bcEncryptProgress(uint64_t size, uint64_t offset, void *usrptr);
4455
int bcDecryptProgress(uint64_t size, uint64_t offset, void *usrptr);
4556

@@ -61,6 +72,9 @@ DevPtr bcCreateBlkDev(const QString &device);
6172
EncryptVersion bcDevEncryptVersion(const QString &device);
6273
int bcDevEncryptStatus(const QString &device, disk_encrypt::EncryptStates *status);
6374
bool bcIsMounted(const QString &device);
75+
quint64 bcGetBlockSize(const QString &device);
76+
77+
bool bcMoveFsForward(const QString &device);
6478
} // namespace block_device_utils
6579

6680
namespace utils {

0 commit comments

Comments
 (0)