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