* See the License for the specific language governing permissions and
* limitations under the License
*/
+
+#include <linux/dm-ioctl.h>
+#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <strings.h>
#include <blkid.h>
-
+#include <string.h>
+#include <iomanip>
#include <string>
+#include <sstream>
#include <iostream>
+#include <memory>
+#include <klay/error.h>
+#include <klay/exception.h>
#include <klay/audit/dlog-sink.h>
#include <upgrade-support.h>
-#include <internal-encryption-common.h>
-#include <engine/encryption/dmcrypt-engine.h>
+#include "progress-bar.h"
+
+#define DM_MAX_BUFFER_SIZE 4096
+#define DM_KEY_MIN_LEN_BYTE 32
+#define DM_DEFAULT_LABEL_NAME "userdata"
+#define DM_DEFAULT_CRYPTO_NAME "aes-cbc-essiv:sha256"
audit::LogSink *SINK = nullptr;
namespace ode {
+const char *INTERNAL_PATH = "/opt/usr";
+
struct AbstractDevice {
AbstractDevice() {}
virtual ~AbstractDevice() {}
void ProgressBar::update(unsigned) {}
void ProgressBar::done(void) {}
+//Hot fix for urgent issue - start, TODO : It should be removed.
+unsigned long getBlockCount(const std::string &src)
+{
+ int fd = open(src.c_str(), O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ unsigned long size = 0;
+ if ((ioctl(fd, BLKGETSIZE, &size)) == -1)
+ size = 0;
+ close(fd);
+
+ return size;
+}
+
+const std::string convertToHex(const BinaryData &binary)
+{
+ std::stringstream hex;
+
+ hex << std::hex << std::setfill('0');
+ for (unsigned int byte : binary) {
+ hex << std::setw(2) << byte;
+ }
+ return hex.str();
+}
+
+void initDMIoctl(char *buf, size_t size, const std::string &name, unsigned flags)
+{
+ struct dm_ioctl *io = (struct dm_ioctl *)buf;
+
+ ::memset(io, 0, size);
+ io->data_size = size;
+ io->data_start = sizeof(struct dm_ioctl);
+ io->version[0] = 4;
+ io->version[1] = 0;
+ io->version[2] = 0;
+ io->flags = flags;
+ ::memset(io->name, 0, sizeof(io->name));
+ ::strncpy(io->name, name.c_str(), sizeof(io->name) - 1);
+}
+
+BinaryData sanitizeKey(const BinaryData &key)
+{
+ if (key.size() < DM_KEY_MIN_LEN_BYTE)
+ throw runtime::Exception("Size of key smaller than minimum 32B");
+ BinaryData sanitized(key);
+ sanitized.resize(DM_KEY_MIN_LEN_BYTE);
+ return sanitized;
+}
+
+const std::string createCryptoBlkDev(const std::string &realBlkDev,
+ const std::string &mountName,
+ const BinaryData &key,
+ std::string cryptoTypeName)
+{
+ auto blockCount = getBlockCount(realBlkDev);
+ std::string cryptoBlkDev;
+ int fd = -1;
+
+ /*
+ * dmBuf |-------------------------------------------------| DM_MAX_BUFFER_SIZE(4096)
+ */
+ char dmBuf[DM_MAX_BUFFER_SIZE]; // first: for dm_io, dm_ts
+
+ // Open dm control IOCTL
+ if ((fd = open("/dev/mapper/control", O_RDWR)) < 0) {
+ throw runtime::Exception("Cannot open device-mapper");
+ }
+
+ std::unique_ptr<int, void(*)(int*)> fdPtr(&fd, [](int* fd){ if (fd) ::close(*fd); });
+
+ /*
+ * dmBuf |-------------------------------------------------| DM_MAX_BUFFER_SIZE(4096)
+ * dmIo |----------| size of dm_ioctl
+ */
+ auto dmIo = (struct dm_ioctl *)dmBuf;
+
+ // Create Device (mount_name)
+ initDMIoctl(dmBuf, DM_MAX_BUFFER_SIZE, mountName, 0);
+ if (ioctl(fd, DM_DEV_CREATE, dmBuf) && errno != EBUSY) {
+ throw runtime::Exception("Cannot create dm-crypt device");
+ }
+
+ // Get the device status, in particular, the mount_name of it's device file
+ initDMIoctl(dmBuf, DM_MAX_BUFFER_SIZE, mountName, 0);
+ if (ioctl(fd, DM_DEV_STATUS, dmBuf)) {
+ throw runtime::Exception("Cannot retrieve dm-crypt device status");
+ }
+
+ // Store created device into crypto_blkdev
+ unsigned int dmMinor = (dmIo->dev & 0xff) | ((dmIo->dev >> 12) & 0xfff00);
+ cryptoBlkDev = "/dev/dm-" + std::to_string(dmMinor);
+
+ /*
+ * dmBuf |-------------------------------------------------| DM_MAX_BUFFER_SIZE(4096)
+ * dmIo |----------| size of dm_ioctl
+ * dmTs |--------------| size of dm_target_spec
+ */
+ auto dmTs = (struct dm_target_spec *)(dmBuf + sizeof(struct dm_ioctl));
+
+ // Load the mapping table for this device
+
+ // Force clean-up whole dm_buffer
+ initDMIoctl(dmBuf, DM_MAX_BUFFER_SIZE, mountName, 0);
+ dmIo->target_count = 1;
+ dmTs->status = 0;
+ dmTs->sector_start = 0;
+ dmTs->length = blockCount;
+ ::memset(dmTs->target_type, 0, sizeof(dmTs->target_type));
+ ::strncpy(dmTs->target_type, "crypt", sizeof(dmTs->target_type) - 1);
+
+ /*
+ * dmBuf |-------------------------------------------------| DM_MAX_BUFFER_SIZE(4096)
+ * dmIo |----------| size of dm_ioctl
+ * dmTs |--------------| size of dm_target_spec
+ * cryptParams |---------------------|
+ */
+ char *cryptParams = dmBuf + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+
+ // Store cryptParams
+ size_t cryptParamsSize = DM_MAX_BUFFER_SIZE - (cryptParams - dmBuf);
+ std::string keyHex = convertToHex(key);
+ int ret = snprintf(cryptParams,
+ cryptParamsSize,
+ "%s %s 0 %s 0",
+ cryptoTypeName.c_str(),
+ keyHex.c_str(),
+ realBlkDev.c_str());
+ if (ret < 0) {
+ throw runtime::Exception("snprintf() failed");
+ }
+ if (static_cast<size_t>(ret) >= cryptParamsSize) {
+ throw runtime::Exception("Crypto params didn't fit the device mapper buffer");
+ }
+
+ cryptParams += strlen(cryptParams) + 1;
+ // Align to an 8 byte boundary
+ cryptParams = (char *)(((unsigned long)cryptParams + 7) & ~8);
+ dmTs->next = cryptParams - dmBuf;
+
+ // Table load
+ if (ioctl(fd, DM_TABLE_LOAD, dmBuf) < 0) {
+ throw runtime::Exception("Cannot load dm-crypt mapping table.");
+ }
+
+ // Resume this device to activate it
+ initDMIoctl(dmBuf, DM_MAX_BUFFER_SIZE, mountName, 0);
+ if (ioctl(fd, DM_DEV_SUSPEND, dmBuf)) {
+ throw runtime::Exception("Cannot resume the dm-crypt device");
+ }
+
+ return cryptoBlkDev;
+}
+
+void destroyCryptoBlkDev(const std::string &cryptoBlkDev)
+{
+ char buf[DM_MAX_BUFFER_SIZE];
+ int fd, ret;
+
+ if ((fd = open("/dev/mapper/control", O_RDWR)) < 0)
+ throw runtime::Exception("Cannot open device-mapper");
+
+ initDMIoctl(buf, sizeof(buf), cryptoBlkDev, 0);
+ ret = ioctl(fd, DM_DEV_REMOVE, buf);
+ int err = errno;
+ close(fd);
+
+ if (ret != 0 && err != ENXIO) {
+ throw runtime::Exception("Cannot remove dm-crypt device");
+ }
+}
+
+void DMCryptMount(const std::string &source, const std::string &destination, const BinaryData &key, unsigned int options)
+{
+ // create crypto type device mapping layer to mount the encrypted partition.
+ auto cryptoBlkDev = createCryptoBlkDev(source, DM_DEFAULT_LABEL_NAME, sanitizeKey(key), DM_DEFAULT_CRYPTO_NAME);
+
+ if (::mount(cryptoBlkDev.c_str(), destination.c_str(), "ext4", 0, 0) < 0)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+}
+
+void DMCryptUmount(const std::string &destination)
+{
+ if (::umount(destination.c_str()) && errno != EINVAL && errno != ENOENT)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+
+ destroyCryptoBlkDev(DM_DEFAULT_LABEL_NAME);
+}
+//Hot fix - end
+
} // namespace ode
namespace {
if (argc == 3)
path = argv[2];
- DMCryptEngine dmcrypt(devpath, path, ProgressBar([](unsigned){}));
-
// mount options are ignored by mount()
- dmcrypt.mount(masterKey, 0);
+ DMCryptMount(devpath, path, masterKey, 0);
UpgradeSupport::createUpgradeFlag();
} else if (UMOUNT == argv[1]) {
std::string path = INTERNAL_PATH;
if (argc == 3)
path = argv[2];
- DMCryptEngine dmcrypt(devpath, path, ProgressBar([](int){}));
- dmcrypt.umount();
+ DMCryptUmount(path);
} else if (REMOVE == argv[1]) {
UpgradeSupport::removeMasterKey(devpath);
} else {