Add privileges to APIs
[platform/core/security/ode.git] / server / secure-erase.cpp
1 /*
2  *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16 #include <fstream>
17
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <linux/fs.h>
21 #include <linux/fiemap.h>
22
23 #include <vconf.h>
24 #include <klay/exception.h>
25 #include <klay/filesystem.h>
26 #include <klay/audit/logger.h>
27
28 #include "rmi/secure-erase.h"
29 #include "progress-bar.h"
30 #include "progress-vconf-backend.h"
31 #include "block-device.h"
32 #include "ext4-tool.h"
33
34 #define PRIVILEGE_PLATFORM "http://tizen.org/privilege/internal/default/platform"
35
36 namespace ode {
37
38 namespace {
39 VConfBackend vconfBackend(VCONFKEY_ODE_ERASE_PROGRESS);
40 ProgressBar progressBar(std::bind(&VConfBackend::update, &vconfBackend, std::placeholders::_1));
41
42 static int totalFileCount = 0;
43 static int erasedFileCount = 0;
44
45 static int getTotalFileCount(const std::string &name)
46 {
47         int total = 0;
48         runtime::DirectoryIterator iter(name), end;
49
50         while (iter != end) {
51                 std::string next = name + "/" + iter->getName();
52                 runtime::File file(next);
53                 if (!file.exists()) {
54                         return -1;
55                 }
56
57                 if (file.isFile()) {
58                         total++;
59                 } else if (file.isDirectory()) {
60                         int subTotal = getTotalFileCount(next);
61                         if (subTotal != -1)
62                                 total += subTotal;
63                 }
64                 ++iter;
65         }
66
67         return total;
68 }
69
70 } /* namespace */
71
72 SecureErase::SecureErase(ODEControlContext &ctx) :
73         context(ctx), devicePath("")
74 {
75         context.expose(this, PRIVILEGE_PLATFORM, (int)(SecureErase::erase)(std::string));
76         context.expose(this, PRIVILEGE_PLATFORM, (int)(SecureErase::clean)(std::string));
77 }
78
79 SecureErase::~SecureErase()
80 {
81 }
82
83 int SecureErase::erase(const std::string &name)
84 {
85         auto eraseWorker = [name, this]() {
86                 try {
87                         runtime::File file(name);
88
89                         BlockDevice blockDevice(name);
90                         devicePath = blockDevice.getName();
91
92                         if (file.isFile()) {
93                                 totalFileCount = 1;
94                                 fileErase(name);
95                         } else if (file.isDirectory()) {
96                                 totalFileCount = getTotalFileCount(name);
97                                 erasedFileCount = 0;
98                                 directoryErase(name);
99                         } else if (file.isDevice()) {
100                                 Ext4Tool ext4Tool(name);
101                                 unsigned int totalBlock = ext4Tool.getTotalBlockCount();
102                                 unsigned int blockSize = (unsigned int)blockDevice.getSize();
103
104                                 for (unsigned int i = 0; i < totalBlock; i++) {
105                                         Block block(i * blockSize, blockSize);
106                                         blockDevice.discard(block);
107                                         progressBar.update(i, totalBlock, 1);
108                                 }
109                         }
110                         dropCachePage();
111                         progressBar.done();
112                 } catch (runtime::Exception &e) {}
113         };
114
115         std::thread asyncWork(eraseWorker);
116         asyncWork.detach();
117
118         return 0;
119 }
120
121 int SecureErase::clean(const std::string &name)
122 {
123         try {
124                 runtime::File file(name, O_WRONLY);
125                 if (!file.exists() || !file.isDevice())
126                         return -1;
127         } catch (runtime::Exception &e) {}
128
129         auto cleanWorker = [name, this]() {
130                 try {
131                         BlockDevice blockDevice(name);
132                         unsigned totalBlock, blockSize;
133
134                         Ext4Tool ext4Tool(name);
135                         totalBlock = ext4Tool.getTotalBlockCount();
136                         blockSize = (unsigned int) blockDevice.getSize();
137
138                         for (unsigned int i = 0; i < totalBlock; i++) {
139                                 if (!ext4Tool.isUsedBlock(i)) {
140                                         Block block(i * blockSize, blockSize);
141                                         blockDevice.discard(block);
142                                 }
143
144                                 progressBar.update(i, totalBlock, 1);
145                         }
146                         dropCachePage();
147                         progressBar.done();
148                 } catch (runtime::Exception &e) {}
149         };
150
151         std::thread asyncWork(cleanWorker);
152         asyncWork.detach();
153
154         return 0;
155 }
156
157 int SecureErase::fileErase(const std::string &name)
158 {
159         int ret = 0, fd = 0;
160         int extentBlockCount = 0;
161         char buf[4096] = "";
162         struct fiemap *fmap = (struct fiemap *)buf;
163         struct fiemap_extent *fm_ext = NULL;
164         int count = (sizeof(buf) - sizeof(*fmap)) / sizeof(struct fiemap_extent);
165
166         /* [TBD] stop the related process */
167
168         BlockDevice blockDevice(devicePath);
169
170         ::memset(fmap, 0, sizeof(struct fiemap));
171
172         fd = ::open(name.c_str(), O_RDONLY);
173         if (fd < 0) {
174                 return -1;
175         }
176
177         fmap->fm_length = ~0ULL;
178         fmap->fm_flags = 0;
179         fmap->fm_extent_count = count;
180
181         ret = ::ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fmap);
182         if (ret < 0) {
183                 ::close(fd);
184                 return -1;
185         }
186
187         ::close(fd);
188
189         fm_ext = &fmap->fm_extents[0];
190         extentBlockCount = (int)fmap->fm_mapped_extents;
191
192         for (int i = 0; i < extentBlockCount; i++) {
193                 Block block(fm_ext[i].fe_physical, fm_ext[i].fe_length);
194                 ret = blockDevice.secDiscard(block);
195                 if (ret < 0) {
196                         return -1;
197                 }
198
199                 if (totalFileCount == 1) {
200                         progressBar.update(i, extentBlockCount, 1);
201                 }
202         }
203
204         return ret;
205 }
206
207 int SecureErase::directoryErase(const std::string &name)
208 {
209         runtime::DirectoryIterator iter(name), end;
210         while (iter != end) {
211                 std::string next = name + "/" + iter->getName();
212                 runtime::File file(next);
213                 if (!file.exists()) {
214                         return -1;
215                 }
216
217                 if (file.isFile()) {
218                         fileErase(next);
219                         ::remove(next.c_str());
220                         erasedFileCount++;
221                         progressBar.update(erasedFileCount, totalFileCount, 1);
222                 } else if (file.isDirectory()) {
223                         directoryErase(next);
224                 }
225                 ++iter;
226         }
227
228         fileErase(name);
229         ::rmdir(name.c_str());
230         return 0;
231 }
232
233 void SecureErase::dropCachePage()
234 {
235         std::ofstream file;
236
237         file.open("/proc/sys/vm/drop_caches");
238         if (file.fail()) {
239                 throw runtime::Exception("Failed to access drop_caches file");
240         }
241         file << "3\n";
242         file.close();
243         ::sync();
244
245         return;
246 }
247
248 } // namespace ode