xref: /aosp_15_r20/system/nvram/hal/fake_nvram_storage.cpp (revision 7ba4dab5cc5e3c8f3eb594dcf3b33f99d9214aee)
1*7ba4dab5SXin Li /*
2*7ba4dab5SXin Li  * Copyright (C) 2016 The Android Open Source Project
3*7ba4dab5SXin Li  *
4*7ba4dab5SXin Li  * Licensed under the Apache License, Version 2.0 (the "License");
5*7ba4dab5SXin Li  * you may not use this file except in compliance with the License.
6*7ba4dab5SXin Li  * You may obtain a copy of the License at
7*7ba4dab5SXin Li  *
8*7ba4dab5SXin Li  *      http://www.apache.org/licenses/LICENSE-2.0
9*7ba4dab5SXin Li  *
10*7ba4dab5SXin Li  * Unless required by applicable law or agreed to in writing, software
11*7ba4dab5SXin Li  * distributed under the License is distributed on an "AS IS" BASIS,
12*7ba4dab5SXin Li  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*7ba4dab5SXin Li  * See the License for the specific language governing permissions and
14*7ba4dab5SXin Li  * limitations under the License.
15*7ba4dab5SXin Li  */
16*7ba4dab5SXin Li 
17*7ba4dab5SXin Li #include <nvram/core/storage.h>
18*7ba4dab5SXin Li 
19*7ba4dab5SXin Li #include <errno.h>
20*7ba4dab5SXin Li #include <fcntl.h>
21*7ba4dab5SXin Li #include <stdio.h>
22*7ba4dab5SXin Li #include <sys/stat.h>
23*7ba4dab5SXin Li #include <sys/types.h>
24*7ba4dab5SXin Li #include <unistd.h>
25*7ba4dab5SXin Li 
26*7ba4dab5SXin Li #include <android-base/file.h>
27*7ba4dab5SXin Li #include <android-base/logging.h>
28*7ba4dab5SXin Li #include <android-base/unique_fd.h>
29*7ba4dab5SXin Li 
30*7ba4dab5SXin Li #include <nvram/core/logger.h>
31*7ba4dab5SXin Li 
32*7ba4dab5SXin Li // An NVRAM storage layer implementation backed by the file system.
33*7ba4dab5SXin Li //
34*7ba4dab5SXin Li // NOTE: This does not meet the tamper evidence requirements for
35*7ba4dab5SXin Li // access-controlled NVRAM implementations, since the file system can't provide
36*7ba4dab5SXin Li // sufficient protection against tampering by attackers.
37*7ba4dab5SXin Li 
38*7ba4dab5SXin Li namespace {
39*7ba4dab5SXin Li 
40*7ba4dab5SXin Li // Name of the storage object holding the header.
41*7ba4dab5SXin Li const char kHeaderFileName[] = "header";
42*7ba4dab5SXin Li 
43*7ba4dab5SXin Li // Pattern for space data storage object names.
44*7ba4dab5SXin Li const char kSpaceDataFileNamePattern[] = "space_%08x";
45*7ba4dab5SXin Li 
46*7ba4dab5SXin Li // Temporary file name used in write-rename atomic write operations.
47*7ba4dab5SXin Li const char kTempFileName[] = "temp";
48*7ba4dab5SXin Li 
49*7ba4dab5SXin Li // Maximum size of objects we're willing to read and write.
50*7ba4dab5SXin Li const off_t kMaxFileSize = 2048;
51*7ba4dab5SXin Li 
52*7ba4dab5SXin Li // Buffer size for formatting names.
53*7ba4dab5SXin Li using NameBuffer = char[16];
54*7ba4dab5SXin Li 
55*7ba4dab5SXin Li // Global data directory descriptor.
56*7ba4dab5SXin Li int g_data_dir_fd = -1;
57*7ba4dab5SXin Li 
58*7ba4dab5SXin Li // Formats the storage object name for the given space index.
FormatSpaceFileName(NameBuffer name,uint32_t index)59*7ba4dab5SXin Li bool FormatSpaceFileName(NameBuffer name, uint32_t index) {
60*7ba4dab5SXin Li   int ret =
61*7ba4dab5SXin Li       snprintf(name, sizeof(NameBuffer), kSpaceDataFileNamePattern, index);
62*7ba4dab5SXin Li   return ret >= 0 && ret < static_cast<int>(sizeof(NameBuffer));
63*7ba4dab5SXin Li };
64*7ba4dab5SXin Li 
DeleteFile(const char * name)65*7ba4dab5SXin Li nvram::storage::Status DeleteFile(const char* name) {
66*7ba4dab5SXin Li   if (TEMP_FAILURE_RETRY(unlinkat(g_data_dir_fd, name, 0))) {
67*7ba4dab5SXin Li     if (errno == ENOENT) {
68*7ba4dab5SXin Li       return nvram::storage::Status::kNotFound;
69*7ba4dab5SXin Li     }
70*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to remove " << name;
71*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
72*7ba4dab5SXin Li   }
73*7ba4dab5SXin Li 
74*7ba4dab5SXin Li   return nvram::storage::Status::kSuccess;
75*7ba4dab5SXin Li }
76*7ba4dab5SXin Li 
77*7ba4dab5SXin Li // Loads the storage object identified by |name|.
LoadFile(const char * name,nvram::Blob * blob)78*7ba4dab5SXin Li nvram::storage::Status LoadFile(const char* name, nvram::Blob* blob) {
79*7ba4dab5SXin Li   android::base::unique_fd data_file_fd(
80*7ba4dab5SXin Li       TEMP_FAILURE_RETRY(openat(g_data_dir_fd, name, O_RDONLY)));
81*7ba4dab5SXin Li   if (data_file_fd.get() < 0) {
82*7ba4dab5SXin Li     if (errno == ENOENT) {
83*7ba4dab5SXin Li       return nvram::storage::Status::kNotFound;
84*7ba4dab5SXin Li     }
85*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to open " << name;
86*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
87*7ba4dab5SXin Li   }
88*7ba4dab5SXin Li 
89*7ba4dab5SXin Li   struct stat data_file_stat;
90*7ba4dab5SXin Li   if (TEMP_FAILURE_RETRY(fstat(data_file_fd.get(), &data_file_stat))) {
91*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to stat " << name;
92*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
93*7ba4dab5SXin Li   }
94*7ba4dab5SXin Li 
95*7ba4dab5SXin Li   if (data_file_stat.st_size > kMaxFileSize) {
96*7ba4dab5SXin Li     LOG(ERROR) << "Bad size for " << name << ":" << data_file_stat.st_size;
97*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
98*7ba4dab5SXin Li   }
99*7ba4dab5SXin Li 
100*7ba4dab5SXin Li   if (!blob->Resize(data_file_stat.st_size)) {
101*7ba4dab5SXin Li     LOG(ERROR) << "Failed to allocate read buffer for " << name;
102*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
103*7ba4dab5SXin Li   }
104*7ba4dab5SXin Li 
105*7ba4dab5SXin Li   if (!android::base::ReadFully(data_file_fd.get(), blob->data(),
106*7ba4dab5SXin Li                                 blob->size())) {
107*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to read " << name;
108*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
109*7ba4dab5SXin Li   }
110*7ba4dab5SXin Li 
111*7ba4dab5SXin Li   return nvram::storage::Status::kSuccess;
112*7ba4dab5SXin Li }
113*7ba4dab5SXin Li 
114*7ba4dab5SXin Li // Writes blob to the storage object indicated by |name|.
StoreFile(const char * name,const nvram::Blob & blob)115*7ba4dab5SXin Li nvram::storage::Status StoreFile(const char* name, const nvram::Blob& blob) {
116*7ba4dab5SXin Li   android::base::unique_fd data_file_fd(TEMP_FAILURE_RETRY(
117*7ba4dab5SXin Li       openat(g_data_dir_fd, kTempFileName, O_WRONLY | O_CREAT | O_TRUNC,
118*7ba4dab5SXin Li              S_IRUSR | S_IWUSR)));
119*7ba4dab5SXin Li   if (data_file_fd.get() < 0) {
120*7ba4dab5SXin Li     if (errno == ENOENT) {
121*7ba4dab5SXin Li       return nvram::storage::Status::kNotFound;
122*7ba4dab5SXin Li     }
123*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to open " << kTempFileName;
124*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
125*7ba4dab5SXin Li   }
126*7ba4dab5SXin Li 
127*7ba4dab5SXin Li   if (!android::base::WriteFully(data_file_fd.get(), blob.data(),
128*7ba4dab5SXin Li                                  blob.size())) {
129*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to write " << kTempFileName;
130*7ba4dab5SXin Li     DeleteFile(kTempFileName);
131*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
132*7ba4dab5SXin Li   }
133*7ba4dab5SXin Li 
134*7ba4dab5SXin Li   // Force the file contents to be written to disk.
135*7ba4dab5SXin Li   if (TEMP_FAILURE_RETRY(fdatasync(data_file_fd.get()))) {
136*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to sync " << kTempFileName;
137*7ba4dab5SXin Li     DeleteFile(kTempFileName);
138*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
139*7ba4dab5SXin Li   }
140*7ba4dab5SXin Li 
141*7ba4dab5SXin Li   data_file_fd.reset();
142*7ba4dab5SXin Li 
143*7ba4dab5SXin Li   // Move the file into place.
144*7ba4dab5SXin Li   if (TEMP_FAILURE_RETRY(
145*7ba4dab5SXin Li           renameat(g_data_dir_fd, kTempFileName, g_data_dir_fd, name))) {
146*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to move " << kTempFileName << " to " << name;
147*7ba4dab5SXin Li     DeleteFile(kTempFileName);
148*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
149*7ba4dab5SXin Li   }
150*7ba4dab5SXin Li 
151*7ba4dab5SXin Li   // Force the directory meta data to be written to disk.
152*7ba4dab5SXin Li   if (TEMP_FAILURE_RETRY(fsync(g_data_dir_fd))) {
153*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to sync data directory";
154*7ba4dab5SXin Li     return nvram::storage::Status::kStorageError;
155*7ba4dab5SXin Li   }
156*7ba4dab5SXin Li 
157*7ba4dab5SXin Li   return nvram::storage::Status::kSuccess;
158*7ba4dab5SXin Li }
159*7ba4dab5SXin Li 
160*7ba4dab5SXin Li }  // namespace
161*7ba4dab5SXin Li 
162*7ba4dab5SXin Li // Initializes the storage layer with the provided data directory descriptor.
InitStorage(int data_dir_fd)163*7ba4dab5SXin Li void InitStorage(int data_dir_fd) {
164*7ba4dab5SXin Li   g_data_dir_fd = data_dir_fd;
165*7ba4dab5SXin Li }
166*7ba4dab5SXin Li 
167*7ba4dab5SXin Li namespace nvram {
168*7ba4dab5SXin Li namespace storage {
169*7ba4dab5SXin Li 
LoadHeader(Blob * blob)170*7ba4dab5SXin Li Status LoadHeader(Blob* blob) {
171*7ba4dab5SXin Li   return LoadFile(kHeaderFileName, blob);
172*7ba4dab5SXin Li }
173*7ba4dab5SXin Li 
StoreHeader(const Blob & blob)174*7ba4dab5SXin Li Status StoreHeader(const Blob& blob) {
175*7ba4dab5SXin Li   return StoreFile(kHeaderFileName, blob);
176*7ba4dab5SXin Li }
177*7ba4dab5SXin Li 
LoadSpace(uint32_t index,Blob * blob)178*7ba4dab5SXin Li Status LoadSpace(uint32_t index, Blob* blob) {
179*7ba4dab5SXin Li   NameBuffer name;
180*7ba4dab5SXin Li   if (!FormatSpaceFileName(name, index)) {
181*7ba4dab5SXin Li     return Status::kStorageError;
182*7ba4dab5SXin Li   }
183*7ba4dab5SXin Li   return LoadFile(name, blob);
184*7ba4dab5SXin Li }
185*7ba4dab5SXin Li 
StoreSpace(uint32_t index,const Blob & blob)186*7ba4dab5SXin Li Status StoreSpace(uint32_t index, const Blob& blob) {
187*7ba4dab5SXin Li   NameBuffer name;
188*7ba4dab5SXin Li   if (!FormatSpaceFileName(name, index)) {
189*7ba4dab5SXin Li     return Status::kStorageError;
190*7ba4dab5SXin Li   }
191*7ba4dab5SXin Li   return StoreFile(name, blob);
192*7ba4dab5SXin Li }
193*7ba4dab5SXin Li 
DeleteSpace(uint32_t index)194*7ba4dab5SXin Li Status DeleteSpace(uint32_t index) {
195*7ba4dab5SXin Li   NameBuffer name;
196*7ba4dab5SXin Li   if (!FormatSpaceFileName(name, index)) {
197*7ba4dab5SXin Li     return Status::kStorageError;
198*7ba4dab5SXin Li   }
199*7ba4dab5SXin Li 
200*7ba4dab5SXin Li   return DeleteFile(name);
201*7ba4dab5SXin Li }
202*7ba4dab5SXin Li 
203*7ba4dab5SXin Li }  // namespace storage
204*7ba4dab5SXin Li }  // namespace nvram
205