Add secure-erase 67/99567/18
authorseolheui,kim <s414.kim@samsung.com>
Wed, 23 Nov 2016 08:58:35 +0000 (17:58 +0900)
committerseolheui,kim <s414.kim@samsung.com>
Wed, 30 Nov 2016 01:39:12 +0000 (10:39 +0900)
Change-Id: I383d341a158049689b4bcc39e2bf7b5af4f1421c
Signed-off-by: seolheui,kim <s414.kim@samsung.com>
rmi/secure-erase.h
server/CMakeLists.txt
server/block-device.cpp [new file with mode: 0644]
server/block-device.h [new file with mode: 0644]
server/secure-erase.cpp

index 2eb47356dcaacfaf1f5ca83f6141cd6f8c891d81..48facda12124a3029f5a838fbe75473be96449a5 100644 (file)
@@ -33,8 +33,13 @@ public:
        int erase(const std::string& name);
        int clean(const std::string& name);
 
+private:
+       int fileErase(const std::string& name);
+       int directoryErase(const std::string& name);
+       void dropCachePage();
 private:
        ODEControlContext& context;
+       std::string devicePath;
 };
 
 } // namespace ode
index 94a688d78284c626ea9a545f44dc9c0931bc6ecb..e32abb2767a6052cad2ffa3e9a0e469f51fdaf0d 100644 (file)
@@ -17,6 +17,7 @@ SET(SERVER_SRCS       main.cpp
                                server.cpp
                                ext4-tool.cpp
                                secure-erase.cpp
+                               block-device.cpp
                                internal-encryption.cpp
                                external-encryption.cpp
                                engine/ext4-engine.cpp
diff --git a/server/block-device.cpp b/server/block-device.cpp
new file mode 100644 (file)
index 0000000..184ef88
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include <string.h>
+
+#include <klay/filesystem.h>
+#include <klay/exception.h>
+
+#include "block-device.h"
+
+namespace ode {
+
+BlockDevice::BlockDevice(const std::string &path) : name("")
+{
+       int ret = 0;
+       runtime::File file(path);
+       if (!file.exists()) {
+               throw runtime::Exception("target doesn't exist");
+       }
+
+       if (!file.isDevice()) {
+               createDeviceList();
+               evaluateDevice(path);
+       } else {
+               name = path;
+       }
+
+       if (name != "") {
+               int descriptor = ::open(name.c_str(), O_RDONLY);
+               if (descriptor > 0) {
+                       ret = ::ioctl(descriptor, FIGETBSZ, &blockSize);
+                       if (ret < 0) {
+                               ::close(descriptor);
+                               throw runtime::Exception("Failed to get block size");
+                       }
+               }
+               ::close(descriptor);
+       } else {
+               throw runtime::Exception("Cannot find device name");
+       }
+}
+
+BlockDevice::~BlockDevice()
+{
+}
+
+int BlockDevice::open(int flags)
+{
+       int descriptor = 0;
+
+       if (name != "") {
+               descriptor = ::open(name.c_str(), flags);
+               return descriptor;
+       }
+
+       return -1;
+}
+
+void BlockDevice::close(int descriptor)
+{
+       int ret = 0;
+
+       ret = ::close(descriptor);
+       if (ret < 0) {
+               throw runtime::Exception("Cannot close descriptor");
+       }
+       return;
+}
+
+int BlockDevice::discard(const Block &block)
+{
+       int devFd = 0;
+       unsigned long long range[2];
+
+       devFd = BlockDevice::open(O_WRONLY);
+       if (devFd < 0) {
+               return -1;
+       }
+
+       range[0] = block.physicalOffset;
+       range[1] = block.length;
+
+       int ret = ::ioctl(devFd, BLKDISCARD, &range);
+
+       BlockDevice::close(devFd);
+
+       return ret;
+}
+
+int BlockDevice::secDiscard(const Block &block)
+{
+       int devFd = 0;
+       unsigned long long range[2];
+
+       devFd = BlockDevice::open(O_WRONLY);
+       if (devFd < 0) {
+               return -1;
+       }
+
+       range[0] = block.physicalOffset;
+       range[1] = block.length;
+
+       int ret = ::ioctl(devFd, BLKSECDISCARD, &range);
+
+       BlockDevice::close(devFd);
+
+       return ret;
+}
+
+const std::string &BlockDevice::getName() const
+{
+       if (name == "") {
+               throw runtime::Exception("Cannot get device name");
+       }
+       return name;
+}
+
+int BlockDevice::getSize()
+{
+       if (name == "") {
+               throw runtime::Exception("Cannot get device name");
+       }
+       return blockSize;
+}
+
+void BlockDevice::createDeviceList()
+{
+       char deviceName[PATH_MAX] = "";
+       char source[PATH_MAX] = "";
+       char filesystemType[PATH_MAX] = "";
+       std::string deviceInfo = "";
+
+       std::ifstream file("/etc/mtab");
+       if (file.fail()) {
+               throw runtime::Exception("/etc/mtab doesn't exist");
+       }
+
+       while (std::getline(file, deviceInfo)) {
+               if (::sscanf(deviceInfo.c_str(), "%s %s %s %*s %*d %*d",
+                                        deviceName, source, filesystemType) == 3) {
+                       int fd = ::open(deviceName, O_WRONLY);
+                       if (fd < 0) {
+                               continue;
+                       }
+
+                       if (strcmp(filesystemType, "ext2") && strcmp(filesystemType, "ext3")
+                               && strcmp(filesystemType, "ext4")) {
+                               ::close(fd);
+                               continue;
+                       }
+
+                       runtime::File device(deviceName);
+                       if (!device.exists()) {
+                               ::close(fd);
+                               continue;
+                       }
+
+                       if (device.isDevice()) {
+                               deviceList.insert(std::make_pair(source, deviceName));
+                       }
+                       ::close(fd);
+               }
+       }
+
+       return;
+}
+
+void BlockDevice::evaluateDevice(const std::string &path)
+{
+       DeviceListIterator matchedDevice = deviceList.find(path);
+       const std::string &subStr = path;
+       std::size_t pos = subStr.size();
+
+       if (matchedDevice != deviceList.end()) {
+               name = matchedDevice->second;
+               return;
+       }
+
+       while ((pos = subStr.rfind('/', pos - 1)) != std::string::npos && pos != 0) {
+               std::string subPath = subStr.substr(0, pos);
+               matchedDevice = deviceList.find(subPath);
+               if (matchedDevice != deviceList.end()) {
+                       name = matchedDevice->second;
+                       return;
+               }
+       }
+}
+
+} //namespace ode
diff --git a/server/block-device.h b/server/block-device.h
new file mode 100644 (file)
index 0000000..095da51
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#ifndef __BLOCK_DEVICE_H__
+#define __BLOCK_DEVICE_H__
+
+#include <unordered_map>
+#include <fstream>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <linux/fs.h>
+
+#include <klay/filesystem.h>
+
+namespace ode {
+
+class Block {
+public:
+       template <typename OffsetType, typename LengthType>
+       Block(OffsetType offset, LengthType len) : physicalOffset(offset), length(len) {}
+       ~Block() {}
+
+       unsigned long long physicalOffset;
+       unsigned long long length;
+};
+
+class BlockDevice final {
+public:
+       typedef std::unordered_map<std::string, std::string> DeviceList;
+       typedef DeviceList::const_iterator DeviceListIterator;
+
+       BlockDevice(const std::string &path);
+       BlockDevice(const BlockDevice &) = delete;
+       BlockDevice(BlockDevice &&) = delete;
+       ~BlockDevice();
+
+       BlockDevice &operator=(const BlockDevice &) = delete;
+       BlockDevice &operator=(BlockDevice &&) = delete;
+
+       int open(int flags);
+       void close(int descriptor);
+
+       int discard(const Block &block);
+       int secDiscard(const Block &block);
+
+       const std::string &getName() const;
+       int getSize();
+
+private:
+       void createDeviceList();
+       void evaluateDevice(const std::string &path);
+
+private:
+       std::string name;
+       int blockSize;
+
+       DeviceList deviceList;
+};
+
+} // namespace ode
+
+#endif /* __BLOCK_DEVICE_H__ */
index a0afbecef5b5f3245b6e459fdbe1f96f9a12e902..ab10b287ec4361af5be82e440299df4ce032f412 100644 (file)
  *  See the License for the specific language governing permissions and
  *  limitations under the License
  */
+#include <fstream>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+
+#include <klay/exception.h>
 #include <klay/filesystem.h>
 #include <klay/audit/logger.h>
 
 #include "rmi/secure-erase.h"
+#include "block-device.h"
+#include "ext4-tool.h"
 
 namespace ode {
 
-SecureErase::SecureErase(ODEControlContextctx) :
-       context(ctx)
+SecureErase::SecureErase(ODEControlContext &ctx) :
+       context(ctx), devicePath("")
 {
        context.registerParametricMethod(this, "", (int)(SecureErase::erase)(std::string));
        context.registerParametricMethod(this, "", (int)(SecureErase::clean)(std::string));
@@ -31,16 +41,160 @@ SecureErase::~SecureErase()
 {
 }
 
-int SecureErase::erase(const std::string& name)
+int SecureErase::erase(const std::string &name)
+{
+       int ret = -1;
+       try {
+               runtime::File file(name);
+               if (!file.exists()) {
+                       return -1;
+               }
+
+               BlockDevice blockDevice(name);
+               devicePath = blockDevice.getName();
+
+               if (file.isFile()) {
+                       /* TBD */
+                       ret = fileErase(name);
+               } else if (file.isDirectory()) {
+                       /* TBD */
+                       ret = directoryErase(name);
+               } else if (file.isDevice()) {
+                       Ext4Tool ext4Tool(name);
+                       unsigned int i, totalBlock = ext4Tool.getTotalBlockCount();
+                       unsigned int blockSize = (unsigned int)blockDevice.getSize();
+
+                       for (i = 0; i < totalBlock; i++) {
+                               Block block(i*blockSize, blockSize);
+                               ret = blockDevice.discard(block);
+                               if (ret != 0) {
+                                       return -1;
+                               }
+                       }
+               }
+
+               dropCachePage();
+       } catch (runtime::Exception &e) {}
+
+       return ret;
+}
+
+int SecureErase::clean(const std::string &name)
+{
+       int ret = -1;
+       try {
+               BlockDevice blockDevice(name);
+               runtime::File file(name, O_WRONLY);
+               if (!file.exists() || !file.isDevice()) {
+                       return -1;
+               }
+
+               Ext4Tool ext4Tool(name);
+               unsigned int i, totalBlock = ext4Tool.getTotalBlockCount();
+               unsigned int blockSize = (unsigned int) blockDevice.getSize();
+
+               for (i = 0; i < totalBlock; i++) {
+                       if (!ext4Tool.isUsedBlock(i)) {
+                               Block block(i*blockSize, blockSize);
+                               ret = blockDevice.discard(block);
+                               if (ret != 0) {
+                                       return -1;
+                               }
+                       }
+               }
+
+               dropCachePage();
+       } catch (runtime::Exception &e) {}
+
+       return ret;
+}
+
+int SecureErase::fileErase(const std::string &name)
 {
-       return -1;
+       int ret = 0, fd = 0;
+       int extentBlockCount = 0;
+       char buf[4096] = "";
+       struct fiemap *fmap = (struct fiemap *)buf;
+       struct fiemap_extent *fm_ext = NULL;
+       int count = (sizeof(buf) - sizeof(*fmap)) / sizeof(struct fiemap_extent);
+
+       /* [TBD] stop the related process */
+
+       BlockDevice blockDevice(devicePath);
+
+       ::memset(fmap, 0, sizeof(struct fiemap));
+
+       fd = ::open(name.c_str(), O_RDONLY);
+       if (fd < 0) {
+               return -1;
+       }
+
+       fmap->fm_length = ~0ULL;
+       fmap->fm_flags = 0;
+       fmap->fm_extent_count = count;
+
+       ret = ::ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fmap);
+       if (ret < 0) {
+               ::close(fd);
+               return -1;
+       }
+
+       ::close(fd);
+
+       fm_ext = &fmap->fm_extents[0];
+       extentBlockCount = (int)fmap->fm_mapped_extents;
+
+       for (int i = 0; i < extentBlockCount; i++) {
+               Block block(fm_ext[i].fe_physical, fm_ext[i].fe_length);
+               ret = blockDevice.secDiscard(block);
+               if (ret < 0) {
+                       return -1;
+               }
+       }
+
+       return ret;
 }
 
-int SecureErase::clean(const std::string& name)
+int SecureErase::directoryErase(const std::string &name)
 {
-       return -1;
+       int ret = 0;
+
+       runtime::DirectoryIterator iter(name), end;
+       while (iter != end) {
+               std::string next = name + "/" + iter->getName();
+               runtime::File file(next);
+               if (!file.exists()) {
+                       return -1;
+               }
+
+               if (file.isFile()) {
+                       fileErase(next);
+                       ::remove(next.c_str());
+               } else if (file.isDirectory()) {
+                       directoryErase(next);
+               }
+               ++iter;
+       }
+
+       fileErase(name);
+       ::rmdir(name.c_str());
+
+       return ret;
 }
 
+void SecureErase::dropCachePage()
+{
+       std::ofstream file;
+
+       file.open("/proc/sys/vm/drop_caches");
+       if (file.fail()) {
+               throw runtime::Exception("Failed to access drop_caches file");
+       }
+       file << "3\n";
+       file.close();
+       ::sync();
 
+       return;
+}
 
 } // namespace ode