xref: /aosp_15_r20/system/vold/EncryptInplace.cpp (revision f40fafd4c6c2594924d919feffc1a1fd6e3b30f3)
1*f40fafd4SAndroid Build Coastguard Worker /*
2*f40fafd4SAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*f40fafd4SAndroid Build Coastguard Worker  *
4*f40fafd4SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*f40fafd4SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*f40fafd4SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*f40fafd4SAndroid Build Coastguard Worker  *
8*f40fafd4SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*f40fafd4SAndroid Build Coastguard Worker  *
10*f40fafd4SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*f40fafd4SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*f40fafd4SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f40fafd4SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*f40fafd4SAndroid Build Coastguard Worker  * limitations under the License.
15*f40fafd4SAndroid Build Coastguard Worker  */
16*f40fafd4SAndroid Build Coastguard Worker 
17*f40fafd4SAndroid Build Coastguard Worker #include "EncryptInplace.h"
18*f40fafd4SAndroid Build Coastguard Worker 
19*f40fafd4SAndroid Build Coastguard Worker #include <ext4_utils/ext4.h>
20*f40fafd4SAndroid Build Coastguard Worker #include <ext4_utils/ext4_utils.h>
21*f40fafd4SAndroid Build Coastguard Worker #include <f2fs_sparseblock.h>
22*f40fafd4SAndroid Build Coastguard Worker #include <fcntl.h>
23*f40fafd4SAndroid Build Coastguard Worker 
24*f40fafd4SAndroid Build Coastguard Worker #include <algorithm>
25*f40fafd4SAndroid Build Coastguard Worker #include <vector>
26*f40fafd4SAndroid Build Coastguard Worker 
27*f40fafd4SAndroid Build Coastguard Worker #include <android-base/logging.h>
28*f40fafd4SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
29*f40fafd4SAndroid Build Coastguard Worker 
30*f40fafd4SAndroid Build Coastguard Worker enum EncryptInPlaceError {
31*f40fafd4SAndroid Build Coastguard Worker     kSuccess,
32*f40fafd4SAndroid Build Coastguard Worker     kFailed,
33*f40fafd4SAndroid Build Coastguard Worker     kFilesystemNotFound,
34*f40fafd4SAndroid Build Coastguard Worker };
35*f40fafd4SAndroid Build Coastguard Worker 
round_up(uint64_t val,size_t amount)36*f40fafd4SAndroid Build Coastguard Worker static uint64_t round_up(uint64_t val, size_t amount) {
37*f40fafd4SAndroid Build Coastguard Worker     if (val % amount) val += amount - (val % amount);
38*f40fafd4SAndroid Build Coastguard Worker     return val;
39*f40fafd4SAndroid Build Coastguard Worker }
40*f40fafd4SAndroid Build Coastguard Worker 
41*f40fafd4SAndroid Build Coastguard Worker class InPlaceEncrypter {
42*f40fafd4SAndroid Build Coastguard Worker   public:
43*f40fafd4SAndroid Build Coastguard Worker     bool EncryptInPlace(const std::string& crypto_blkdev, const std::string& real_blkdev,
44*f40fafd4SAndroid Build Coastguard Worker                         uint64_t nr_sec);
45*f40fafd4SAndroid Build Coastguard Worker     bool ProcessUsedBlock(uint64_t block_num);
46*f40fafd4SAndroid Build Coastguard Worker 
47*f40fafd4SAndroid Build Coastguard Worker   private:
48*f40fafd4SAndroid Build Coastguard Worker     // aligned 32K writes tends to make flash happy.
49*f40fafd4SAndroid Build Coastguard Worker     // SD card association recommends it.
50*f40fafd4SAndroid Build Coastguard Worker     static const size_t kIOBufferSize = 32768;
51*f40fafd4SAndroid Build Coastguard Worker 
52*f40fafd4SAndroid Build Coastguard Worker     // Avoid spamming the logs.  Print the "Encrypting blocks" log message once
53*f40fafd4SAndroid Build Coastguard Worker     // every 10000 blocks (which is usually every 40 MB or so), and once at the end.
54*f40fafd4SAndroid Build Coastguard Worker     static const int kLogInterval = 10000;
55*f40fafd4SAndroid Build Coastguard Worker 
56*f40fafd4SAndroid Build Coastguard Worker     std::string DescribeFilesystem();
57*f40fafd4SAndroid Build Coastguard Worker     void InitFs(const std::string& fs_type, uint64_t blocks_to_encrypt, uint64_t total_blocks,
58*f40fafd4SAndroid Build Coastguard Worker                 unsigned int block_size);
59*f40fafd4SAndroid Build Coastguard Worker     void UpdateProgress(size_t blocks, bool done);
60*f40fafd4SAndroid Build Coastguard Worker     bool EncryptPendingData();
61*f40fafd4SAndroid Build Coastguard Worker     bool DoEncryptInPlace();
62*f40fafd4SAndroid Build Coastguard Worker 
63*f40fafd4SAndroid Build Coastguard Worker     // ext4 methods
64*f40fafd4SAndroid Build Coastguard Worker     bool ReadExt4BlockBitmap(uint32_t group, uint8_t* buf);
65*f40fafd4SAndroid Build Coastguard Worker     uint64_t FirstBlockInGroup(uint32_t group);
66*f40fafd4SAndroid Build Coastguard Worker     uint32_t NumBlocksInGroup(uint32_t group);
67*f40fafd4SAndroid Build Coastguard Worker     uint32_t NumBaseMetaBlocksInGroup(uint64_t group);
68*f40fafd4SAndroid Build Coastguard Worker     EncryptInPlaceError EncryptInPlaceExt4();
69*f40fafd4SAndroid Build Coastguard Worker 
70*f40fafd4SAndroid Build Coastguard Worker     // f2fs methods
71*f40fafd4SAndroid Build Coastguard Worker     EncryptInPlaceError EncryptInPlaceF2fs();
72*f40fafd4SAndroid Build Coastguard Worker 
73*f40fafd4SAndroid Build Coastguard Worker     std::string real_blkdev_;
74*f40fafd4SAndroid Build Coastguard Worker     std::string crypto_blkdev_;
75*f40fafd4SAndroid Build Coastguard Worker     uint64_t nr_sec_;
76*f40fafd4SAndroid Build Coastguard Worker 
77*f40fafd4SAndroid Build Coastguard Worker     android::base::unique_fd realfd_;
78*f40fafd4SAndroid Build Coastguard Worker     android::base::unique_fd cryptofd_;
79*f40fafd4SAndroid Build Coastguard Worker 
80*f40fafd4SAndroid Build Coastguard Worker     std::string fs_type_;
81*f40fafd4SAndroid Build Coastguard Worker     uint64_t blocks_done_;
82*f40fafd4SAndroid Build Coastguard Worker     uint64_t blocks_to_encrypt_;
83*f40fafd4SAndroid Build Coastguard Worker     unsigned int block_size_;
84*f40fafd4SAndroid Build Coastguard Worker 
85*f40fafd4SAndroid Build Coastguard Worker     std::vector<uint8_t> io_buffer_;
86*f40fafd4SAndroid Build Coastguard Worker     uint64_t first_pending_block_;
87*f40fafd4SAndroid Build Coastguard Worker     size_t blocks_pending_;
88*f40fafd4SAndroid Build Coastguard Worker };
89*f40fafd4SAndroid Build Coastguard Worker 
DescribeFilesystem()90*f40fafd4SAndroid Build Coastguard Worker std::string InPlaceEncrypter::DescribeFilesystem() {
91*f40fafd4SAndroid Build Coastguard Worker     if (fs_type_.empty())
92*f40fafd4SAndroid Build Coastguard Worker         return "full block device " + real_blkdev_;
93*f40fafd4SAndroid Build Coastguard Worker     else
94*f40fafd4SAndroid Build Coastguard Worker         return fs_type_ + " filesystem on " + real_blkdev_;
95*f40fafd4SAndroid Build Coastguard Worker }
96*f40fafd4SAndroid Build Coastguard Worker 
97*f40fafd4SAndroid Build Coastguard Worker // Finishes initializing the encrypter, now that the filesystem details are known.
InitFs(const std::string & fs_type,uint64_t blocks_to_encrypt,uint64_t total_blocks,unsigned int block_size)98*f40fafd4SAndroid Build Coastguard Worker void InPlaceEncrypter::InitFs(const std::string& fs_type, uint64_t blocks_to_encrypt,
99*f40fafd4SAndroid Build Coastguard Worker                               uint64_t total_blocks, unsigned int block_size) {
100*f40fafd4SAndroid Build Coastguard Worker     fs_type_ = fs_type;
101*f40fafd4SAndroid Build Coastguard Worker     blocks_done_ = 0;
102*f40fafd4SAndroid Build Coastguard Worker     blocks_to_encrypt_ = blocks_to_encrypt;
103*f40fafd4SAndroid Build Coastguard Worker     block_size_ = block_size;
104*f40fafd4SAndroid Build Coastguard Worker 
105*f40fafd4SAndroid Build Coastguard Worker     // Allocate the I/O buffer.  kIOBufferSize should always be a multiple of
106*f40fafd4SAndroid Build Coastguard Worker     // the filesystem block size, but round it up just in case.
107*f40fafd4SAndroid Build Coastguard Worker     io_buffer_.resize(round_up(kIOBufferSize, block_size));
108*f40fafd4SAndroid Build Coastguard Worker     first_pending_block_ = 0;
109*f40fafd4SAndroid Build Coastguard Worker     blocks_pending_ = 0;
110*f40fafd4SAndroid Build Coastguard Worker 
111*f40fafd4SAndroid Build Coastguard Worker     LOG(INFO) << "Encrypting " << DescribeFilesystem() << " in-place via " << crypto_blkdev_;
112*f40fafd4SAndroid Build Coastguard Worker     LOG(INFO) << blocks_to_encrypt << " blocks (" << (blocks_to_encrypt * block_size) / 1000000
113*f40fafd4SAndroid Build Coastguard Worker               << " MB) of " << total_blocks << " blocks are in-use";
114*f40fafd4SAndroid Build Coastguard Worker }
115*f40fafd4SAndroid Build Coastguard Worker 
UpdateProgress(size_t blocks,bool done)116*f40fafd4SAndroid Build Coastguard Worker void InPlaceEncrypter::UpdateProgress(size_t blocks, bool done) {
117*f40fafd4SAndroid Build Coastguard Worker     // A log message already got printed for blocks_done_ if one was due, so the
118*f40fafd4SAndroid Build Coastguard Worker     // next message will be due at the *next* block rounded up to kLogInterval.
119*f40fafd4SAndroid Build Coastguard Worker     uint64_t blocks_next_msg = round_up(blocks_done_ + 1, kLogInterval);
120*f40fafd4SAndroid Build Coastguard Worker 
121*f40fafd4SAndroid Build Coastguard Worker     blocks_done_ += blocks;
122*f40fafd4SAndroid Build Coastguard Worker 
123*f40fafd4SAndroid Build Coastguard Worker     // Ensure that a log message gets printed at the end, but not if one was
124*f40fafd4SAndroid Build Coastguard Worker     // already printed due to the block count being a multiple of kLogInterval.
125*f40fafd4SAndroid Build Coastguard Worker     // E.g. we want to show "50000 of 50327" and then "50327 of "50327", but not
126*f40fafd4SAndroid Build Coastguard Worker     // "50000 of 50000" and then redundantly "50000 of 50000" again.
127*f40fafd4SAndroid Build Coastguard Worker     if (done && blocks_done_ % kLogInterval != 0) blocks_next_msg = blocks_done_;
128*f40fafd4SAndroid Build Coastguard Worker 
129*f40fafd4SAndroid Build Coastguard Worker     if (blocks_done_ >= blocks_next_msg)
130*f40fafd4SAndroid Build Coastguard Worker         LOG(DEBUG) << "Encrypted " << blocks_next_msg << " of " << blocks_to_encrypt_ << " blocks";
131*f40fafd4SAndroid Build Coastguard Worker }
132*f40fafd4SAndroid Build Coastguard Worker 
EncryptPendingData()133*f40fafd4SAndroid Build Coastguard Worker bool InPlaceEncrypter::EncryptPendingData() {
134*f40fafd4SAndroid Build Coastguard Worker     if (blocks_pending_ == 0) return true;
135*f40fafd4SAndroid Build Coastguard Worker 
136*f40fafd4SAndroid Build Coastguard Worker     ssize_t bytes = blocks_pending_ * block_size_;
137*f40fafd4SAndroid Build Coastguard Worker     uint64_t offset = first_pending_block_ * block_size_;
138*f40fafd4SAndroid Build Coastguard Worker 
139*f40fafd4SAndroid Build Coastguard Worker     if (pread64(realfd_, &io_buffer_[0], bytes, offset) != bytes) {
140*f40fafd4SAndroid Build Coastguard Worker         PLOG(ERROR) << "Error reading real_blkdev " << real_blkdev_ << " for inplace encrypt";
141*f40fafd4SAndroid Build Coastguard Worker         return false;
142*f40fafd4SAndroid Build Coastguard Worker     }
143*f40fafd4SAndroid Build Coastguard Worker 
144*f40fafd4SAndroid Build Coastguard Worker     if (pwrite64(cryptofd_, &io_buffer_[0], bytes, offset) != bytes) {
145*f40fafd4SAndroid Build Coastguard Worker         PLOG(ERROR) << "Error writing crypto_blkdev " << crypto_blkdev_ << " for inplace encrypt";
146*f40fafd4SAndroid Build Coastguard Worker         return false;
147*f40fafd4SAndroid Build Coastguard Worker     }
148*f40fafd4SAndroid Build Coastguard Worker 
149*f40fafd4SAndroid Build Coastguard Worker     UpdateProgress(blocks_pending_, false);
150*f40fafd4SAndroid Build Coastguard Worker 
151*f40fafd4SAndroid Build Coastguard Worker     blocks_pending_ = 0;
152*f40fafd4SAndroid Build Coastguard Worker     return true;
153*f40fafd4SAndroid Build Coastguard Worker }
154*f40fafd4SAndroid Build Coastguard Worker 
ProcessUsedBlock(uint64_t block_num)155*f40fafd4SAndroid Build Coastguard Worker bool InPlaceEncrypter::ProcessUsedBlock(uint64_t block_num) {
156*f40fafd4SAndroid Build Coastguard Worker     // Flush if the amount of pending data has reached the I/O buffer size, if
157*f40fafd4SAndroid Build Coastguard Worker     // there's a gap between the pending blocks and the next block (due to
158*f40fafd4SAndroid Build Coastguard Worker     // block(s) not being used by the filesystem and thus not needing
159*f40fafd4SAndroid Build Coastguard Worker     // encryption), or if the next block will be aligned to the I/O buffer size.
160*f40fafd4SAndroid Build Coastguard Worker     if (blocks_pending_ * block_size_ == io_buffer_.size() ||
161*f40fafd4SAndroid Build Coastguard Worker         block_num != first_pending_block_ + blocks_pending_ ||
162*f40fafd4SAndroid Build Coastguard Worker         (block_num * block_size_) % io_buffer_.size() == 0) {
163*f40fafd4SAndroid Build Coastguard Worker         if (!EncryptPendingData()) return false;
164*f40fafd4SAndroid Build Coastguard Worker         first_pending_block_ = block_num;
165*f40fafd4SAndroid Build Coastguard Worker     }
166*f40fafd4SAndroid Build Coastguard Worker     blocks_pending_++;
167*f40fafd4SAndroid Build Coastguard Worker     return true;
168*f40fafd4SAndroid Build Coastguard Worker }
169*f40fafd4SAndroid Build Coastguard Worker 
170*f40fafd4SAndroid Build Coastguard Worker // Reads the block bitmap for block group |group| into |buf|.
ReadExt4BlockBitmap(uint32_t group,uint8_t * buf)171*f40fafd4SAndroid Build Coastguard Worker bool InPlaceEncrypter::ReadExt4BlockBitmap(uint32_t group, uint8_t* buf) {
172*f40fafd4SAndroid Build Coastguard Worker     uint64_t offset = (uint64_t)aux_info.bg_desc[group].bg_block_bitmap * info.block_size;
173*f40fafd4SAndroid Build Coastguard Worker     if (pread64(realfd_, buf, info.block_size, offset) != (ssize_t)info.block_size) {
174*f40fafd4SAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to read block bitmap for block group " << group;
175*f40fafd4SAndroid Build Coastguard Worker         return false;
176*f40fafd4SAndroid Build Coastguard Worker     }
177*f40fafd4SAndroid Build Coastguard Worker     return true;
178*f40fafd4SAndroid Build Coastguard Worker }
179*f40fafd4SAndroid Build Coastguard Worker 
FirstBlockInGroup(uint32_t group)180*f40fafd4SAndroid Build Coastguard Worker uint64_t InPlaceEncrypter::FirstBlockInGroup(uint32_t group) {
181*f40fafd4SAndroid Build Coastguard Worker     return aux_info.first_data_block + (group * (uint64_t)info.blocks_per_group);
182*f40fafd4SAndroid Build Coastguard Worker }
183*f40fafd4SAndroid Build Coastguard Worker 
NumBlocksInGroup(uint32_t group)184*f40fafd4SAndroid Build Coastguard Worker uint32_t InPlaceEncrypter::NumBlocksInGroup(uint32_t group) {
185*f40fafd4SAndroid Build Coastguard Worker     uint64_t remaining = aux_info.len_blocks - FirstBlockInGroup(group);
186*f40fafd4SAndroid Build Coastguard Worker     return std::min<uint64_t>(info.blocks_per_group, remaining);
187*f40fafd4SAndroid Build Coastguard Worker }
188*f40fafd4SAndroid Build Coastguard Worker 
189*f40fafd4SAndroid Build Coastguard Worker // In block groups with an uninitialized block bitmap, we only need to encrypt
190*f40fafd4SAndroid Build Coastguard Worker // the backup superblock and the block group descriptors (if they are present).
NumBaseMetaBlocksInGroup(uint64_t group)191*f40fafd4SAndroid Build Coastguard Worker uint32_t InPlaceEncrypter::NumBaseMetaBlocksInGroup(uint64_t group) {
192*f40fafd4SAndroid Build Coastguard Worker     if (!ext4_bg_has_super_block(group)) return 0;
193*f40fafd4SAndroid Build Coastguard Worker     return 1 + aux_info.bg_desc_blocks;
194*f40fafd4SAndroid Build Coastguard Worker }
195*f40fafd4SAndroid Build Coastguard Worker 
EncryptInPlaceExt4()196*f40fafd4SAndroid Build Coastguard Worker EncryptInPlaceError InPlaceEncrypter::EncryptInPlaceExt4() {
197*f40fafd4SAndroid Build Coastguard Worker     if (setjmp(setjmp_env))  // NOLINT
198*f40fafd4SAndroid Build Coastguard Worker         return kFilesystemNotFound;
199*f40fafd4SAndroid Build Coastguard Worker 
200*f40fafd4SAndroid Build Coastguard Worker     if (read_ext(realfd_, 0) != 0) return kFilesystemNotFound;
201*f40fafd4SAndroid Build Coastguard Worker 
202*f40fafd4SAndroid Build Coastguard Worker     LOG(DEBUG) << "ext4 filesystem has " << aux_info.groups << " block groups";
203*f40fafd4SAndroid Build Coastguard Worker 
204*f40fafd4SAndroid Build Coastguard Worker     uint64_t blocks_to_encrypt = 0;
205*f40fafd4SAndroid Build Coastguard Worker     for (uint32_t group = 0; group < aux_info.groups; group++) {
206*f40fafd4SAndroid Build Coastguard Worker         if (aux_info.bg_desc[group].bg_flags & EXT4_BG_BLOCK_UNINIT)
207*f40fafd4SAndroid Build Coastguard Worker             blocks_to_encrypt += NumBaseMetaBlocksInGroup(group);
208*f40fafd4SAndroid Build Coastguard Worker         else
209*f40fafd4SAndroid Build Coastguard Worker             blocks_to_encrypt +=
210*f40fafd4SAndroid Build Coastguard Worker                     (NumBlocksInGroup(group) - aux_info.bg_desc[group].bg_free_blocks_count);
211*f40fafd4SAndroid Build Coastguard Worker     }
212*f40fafd4SAndroid Build Coastguard Worker 
213*f40fafd4SAndroid Build Coastguard Worker     InitFs("ext4", blocks_to_encrypt, aux_info.len_blocks, info.block_size);
214*f40fafd4SAndroid Build Coastguard Worker 
215*f40fafd4SAndroid Build Coastguard Worker     // Encrypt each block group.
216*f40fafd4SAndroid Build Coastguard Worker     std::vector<uint8_t> block_bitmap(info.block_size);
217*f40fafd4SAndroid Build Coastguard Worker     for (uint32_t group = 0; group < aux_info.groups; group++) {
218*f40fafd4SAndroid Build Coastguard Worker         if (!ReadExt4BlockBitmap(group, &block_bitmap[0])) return kFailed;
219*f40fafd4SAndroid Build Coastguard Worker 
220*f40fafd4SAndroid Build Coastguard Worker         uint64_t first_block_num = FirstBlockInGroup(group);
221*f40fafd4SAndroid Build Coastguard Worker         bool uninit = (aux_info.bg_desc[group].bg_flags & EXT4_BG_BLOCK_UNINIT);
222*f40fafd4SAndroid Build Coastguard Worker         uint32_t block_count = uninit ? NumBaseMetaBlocksInGroup(group) : NumBlocksInGroup(group);
223*f40fafd4SAndroid Build Coastguard Worker 
224*f40fafd4SAndroid Build Coastguard Worker         // Encrypt each used block in the block group.
225*f40fafd4SAndroid Build Coastguard Worker         for (uint32_t i = 0; i < block_count; i++) {
226*f40fafd4SAndroid Build Coastguard Worker             if (uninit || bitmap_get_bit(&block_bitmap[0], i))
227*f40fafd4SAndroid Build Coastguard Worker                 ProcessUsedBlock(first_block_num + i);
228*f40fafd4SAndroid Build Coastguard Worker         }
229*f40fafd4SAndroid Build Coastguard Worker     }
230*f40fafd4SAndroid Build Coastguard Worker     return kSuccess;
231*f40fafd4SAndroid Build Coastguard Worker }
232*f40fafd4SAndroid Build Coastguard Worker 
encrypt_f2fs_block(uint64_t block_num,void * _encrypter)233*f40fafd4SAndroid Build Coastguard Worker static int encrypt_f2fs_block(uint64_t block_num, void* _encrypter) {
234*f40fafd4SAndroid Build Coastguard Worker     InPlaceEncrypter* encrypter = reinterpret_cast<InPlaceEncrypter*>(_encrypter);
235*f40fafd4SAndroid Build Coastguard Worker     if (!encrypter->ProcessUsedBlock(block_num)) return -1;
236*f40fafd4SAndroid Build Coastguard Worker     return 0;
237*f40fafd4SAndroid Build Coastguard Worker }
238*f40fafd4SAndroid Build Coastguard Worker 
EncryptInPlaceF2fs()239*f40fafd4SAndroid Build Coastguard Worker EncryptInPlaceError InPlaceEncrypter::EncryptInPlaceF2fs() {
240*f40fafd4SAndroid Build Coastguard Worker     std::unique_ptr<struct f2fs_info, void (*)(struct f2fs_info*)> fs_info(
241*f40fafd4SAndroid Build Coastguard Worker             generate_f2fs_info(realfd_), free_f2fs_info);
242*f40fafd4SAndroid Build Coastguard Worker     if (!fs_info) return kFilesystemNotFound;
243*f40fafd4SAndroid Build Coastguard Worker 
244*f40fafd4SAndroid Build Coastguard Worker     InitFs("f2fs", get_num_blocks_used(fs_info.get()), fs_info->total_blocks, fs_info->block_size);
245*f40fafd4SAndroid Build Coastguard Worker     if (run_on_used_blocks(0, fs_info.get(), encrypt_f2fs_block, this) != 0) return kFailed;
246*f40fafd4SAndroid Build Coastguard Worker     return kSuccess;
247*f40fafd4SAndroid Build Coastguard Worker }
248*f40fafd4SAndroid Build Coastguard Worker 
DoEncryptInPlace()249*f40fafd4SAndroid Build Coastguard Worker bool InPlaceEncrypter::DoEncryptInPlace() {
250*f40fafd4SAndroid Build Coastguard Worker     EncryptInPlaceError rc;
251*f40fafd4SAndroid Build Coastguard Worker 
252*f40fafd4SAndroid Build Coastguard Worker     rc = EncryptInPlaceExt4();
253*f40fafd4SAndroid Build Coastguard Worker     if (rc != kFilesystemNotFound) return rc == kSuccess;
254*f40fafd4SAndroid Build Coastguard Worker 
255*f40fafd4SAndroid Build Coastguard Worker     rc = EncryptInPlaceF2fs();
256*f40fafd4SAndroid Build Coastguard Worker     if (rc != kFilesystemNotFound) return rc == kSuccess;
257*f40fafd4SAndroid Build Coastguard Worker 
258*f40fafd4SAndroid Build Coastguard Worker     LOG(WARNING) << "No recognized filesystem found on " << real_blkdev_
259*f40fafd4SAndroid Build Coastguard Worker                  << ".  Falling back to encrypting the full block device.";
260*f40fafd4SAndroid Build Coastguard Worker     InitFs("", nr_sec_, nr_sec_, 512);
261*f40fafd4SAndroid Build Coastguard Worker     for (uint64_t i = 0; i < nr_sec_; i++) {
262*f40fafd4SAndroid Build Coastguard Worker         if (!ProcessUsedBlock(i)) return false;
263*f40fafd4SAndroid Build Coastguard Worker     }
264*f40fafd4SAndroid Build Coastguard Worker     return true;
265*f40fafd4SAndroid Build Coastguard Worker }
266*f40fafd4SAndroid Build Coastguard Worker 
EncryptInPlace(const std::string & crypto_blkdev,const std::string & real_blkdev,uint64_t nr_sec)267*f40fafd4SAndroid Build Coastguard Worker bool InPlaceEncrypter::EncryptInPlace(const std::string& crypto_blkdev,
268*f40fafd4SAndroid Build Coastguard Worker                                       const std::string& real_blkdev, uint64_t nr_sec) {
269*f40fafd4SAndroid Build Coastguard Worker     real_blkdev_ = real_blkdev;
270*f40fafd4SAndroid Build Coastguard Worker     crypto_blkdev_ = crypto_blkdev;
271*f40fafd4SAndroid Build Coastguard Worker     nr_sec_ = nr_sec;
272*f40fafd4SAndroid Build Coastguard Worker 
273*f40fafd4SAndroid Build Coastguard Worker     realfd_.reset(open64(real_blkdev.c_str(), O_RDONLY | O_CLOEXEC));
274*f40fafd4SAndroid Build Coastguard Worker     if (realfd_ < 0) {
275*f40fafd4SAndroid Build Coastguard Worker         PLOG(ERROR) << "Error opening real_blkdev " << real_blkdev << " for inplace encrypt";
276*f40fafd4SAndroid Build Coastguard Worker         return false;
277*f40fafd4SAndroid Build Coastguard Worker     }
278*f40fafd4SAndroid Build Coastguard Worker 
279*f40fafd4SAndroid Build Coastguard Worker     cryptofd_.reset(open64(crypto_blkdev.c_str(), O_WRONLY | O_CLOEXEC));
280*f40fafd4SAndroid Build Coastguard Worker     if (cryptofd_ < 0) {
281*f40fafd4SAndroid Build Coastguard Worker         PLOG(ERROR) << "Error opening crypto_blkdev " << crypto_blkdev << " for inplace encrypt";
282*f40fafd4SAndroid Build Coastguard Worker         return false;
283*f40fafd4SAndroid Build Coastguard Worker     }
284*f40fafd4SAndroid Build Coastguard Worker 
285*f40fafd4SAndroid Build Coastguard Worker     bool success = DoEncryptInPlace();
286*f40fafd4SAndroid Build Coastguard Worker 
287*f40fafd4SAndroid Build Coastguard Worker     if (success) success &= EncryptPendingData();
288*f40fafd4SAndroid Build Coastguard Worker 
289*f40fafd4SAndroid Build Coastguard Worker     if (success && fsync(cryptofd_) != 0) {
290*f40fafd4SAndroid Build Coastguard Worker         PLOG(ERROR) << "Error syncing " << crypto_blkdev_;
291*f40fafd4SAndroid Build Coastguard Worker         success = false;
292*f40fafd4SAndroid Build Coastguard Worker     }
293*f40fafd4SAndroid Build Coastguard Worker 
294*f40fafd4SAndroid Build Coastguard Worker     if (!success) {
295*f40fafd4SAndroid Build Coastguard Worker         LOG(ERROR) << "In-place encryption of " << DescribeFilesystem() << " failed";
296*f40fafd4SAndroid Build Coastguard Worker         return false;
297*f40fafd4SAndroid Build Coastguard Worker     }
298*f40fafd4SAndroid Build Coastguard Worker     if (blocks_done_ != blocks_to_encrypt_) {
299*f40fafd4SAndroid Build Coastguard Worker         LOG(WARNING) << "blocks_to_encrypt (" << blocks_to_encrypt_
300*f40fafd4SAndroid Build Coastguard Worker                      << ") was incorrect; we actually encrypted " << blocks_done_
301*f40fafd4SAndroid Build Coastguard Worker                      << " blocks.  Encryption progress was inaccurate";
302*f40fafd4SAndroid Build Coastguard Worker     }
303*f40fafd4SAndroid Build Coastguard Worker     // Ensure that the final progress message is printed, so the series of log
304*f40fafd4SAndroid Build Coastguard Worker     // messages ends with e.g. "Encrypted 50327 of 50327 blocks" rather than
305*f40fafd4SAndroid Build Coastguard Worker     // "Encrypted 50000 of 50327 blocks".
306*f40fafd4SAndroid Build Coastguard Worker     UpdateProgress(0, true);
307*f40fafd4SAndroid Build Coastguard Worker 
308*f40fafd4SAndroid Build Coastguard Worker     LOG(INFO) << "Successfully encrypted " << DescribeFilesystem();
309*f40fafd4SAndroid Build Coastguard Worker     return true;
310*f40fafd4SAndroid Build Coastguard Worker }
311*f40fafd4SAndroid Build Coastguard Worker 
312*f40fafd4SAndroid Build Coastguard Worker // Encrypts |real_blkdev| in-place by reading the data from |real_blkdev| and
313*f40fafd4SAndroid Build Coastguard Worker // writing it to |crypto_blkdev|, which should be a dm-crypt or dm-default-key
314*f40fafd4SAndroid Build Coastguard Worker // device backed by |real_blkdev|.  The size to encrypt is |nr_sec| 512-byte
315*f40fafd4SAndroid Build Coastguard Worker // sectors; however, if a filesystem is detected, then its size will be used
316*f40fafd4SAndroid Build Coastguard Worker // instead, and only the in-use blocks of the filesystem will be encrypted.
encrypt_inplace(const std::string & crypto_blkdev,const std::string & real_blkdev,uint64_t nr_sec)317*f40fafd4SAndroid Build Coastguard Worker bool encrypt_inplace(const std::string& crypto_blkdev, const std::string& real_blkdev,
318*f40fafd4SAndroid Build Coastguard Worker                      uint64_t nr_sec) {
319*f40fafd4SAndroid Build Coastguard Worker     LOG(DEBUG) << "encrypt_inplace(" << crypto_blkdev << ", " << real_blkdev << ", " << nr_sec
320*f40fafd4SAndroid Build Coastguard Worker                << ")";
321*f40fafd4SAndroid Build Coastguard Worker 
322*f40fafd4SAndroid Build Coastguard Worker     InPlaceEncrypter encrypter;
323*f40fafd4SAndroid Build Coastguard Worker     return encrypter.EncryptInPlace(crypto_blkdev, real_blkdev, nr_sec);
324*f40fafd4SAndroid Build Coastguard Worker }
325