• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 The Android Open Source Project
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  */
17 
18 #include "host/libs/avb/avb.h"
19 
20 #include <fcntl.h>
21 
22 #include <memory>
23 #include <string>
24 
25 #include <fruit/fruit.h>
26 
27 #include "common/libs/fs/shared_fd.h"
28 #include "common/libs/utils/files.h"
29 #include "common/libs/utils/result.h"
30 #include "common/libs/utils/subprocess.h"
31 #include "host/libs/config/cuttlefish_config.h"
32 #include "host/libs/config/known_paths.h"
33 
34 namespace cuttlefish {
35 namespace {
36 
37 constexpr char kAddHashFooter[] = "add_hash_footer";
38 constexpr char kDefaultAlgorithm[] = "SHA256_RSA4096";
39 constexpr char kInfoImage[] = "info_image";
40 constexpr char kMakeVbmetaImage[] = "make_vbmeta_image";
41 // Taken from external/avb/libavb/avb_slot_verify.c; this define is not in the
42 // headers
43 constexpr size_t kVbMetaMaxSize = 65536ul;
44 
45 }  // namespace
46 
Avb(std::string avbtool_path)47 Avb::Avb(std::string avbtool_path) : avbtool_path_(std::move(avbtool_path)) {}
48 
Avb(std::string avbtool_path,std::string algorithm,std::string key)49 Avb::Avb(std::string avbtool_path, std::string algorithm, std::string key)
50     : avbtool_path_(std::move(avbtool_path)),
51       algorithm_(std::move(algorithm)),
52       key_(std::move(key)) {}
53 
GenerateAddHashFooter(const std::string & image_path,const std::string & partition_name,const off_t partition_size_bytes) const54 Command Avb::GenerateAddHashFooter(const std::string& image_path,
55                                    const std::string& partition_name,
56                                    const off_t partition_size_bytes) const {
57   Command command(avbtool_path_);
58   command.AddParameter(kAddHashFooter);
59   if (!algorithm_.empty()) {
60     command.AddParameter("--algorithm");
61     command.AddParameter(algorithm_);
62   }
63   if (!key_.empty()) {
64     command.AddParameter("--key");
65     command.AddParameter(key_);
66   }
67   command.AddParameter("--image");
68   command.AddParameter(image_path);
69   command.AddParameter("--partition_name");
70   command.AddParameter(partition_name);
71   if (partition_size_bytes > 0) {
72     command.AddParameter("--partition_size");
73     command.AddParameter(partition_size_bytes);
74   } else {
75     command.AddParameter("--dynamic_partition_size");
76   }
77   return command;
78 }
79 
AddHashFooter(const std::string & image_path,const std::string & partition_name,const off_t partition_size_bytes) const80 Result<void> Avb::AddHashFooter(const std::string& image_path,
81                                 const std::string& partition_name,
82                                 const off_t partition_size_bytes) const {
83   auto command =
84       GenerateAddHashFooter(image_path, partition_name, partition_size_bytes);
85   int exit_code = command.Start().Wait();
86   CF_EXPECTF(exit_code == 0, "Failure running {} {}. Exited with status {}",
87              command.Executable(), kAddHashFooter, exit_code);
88   return {};
89 }
90 
GenerateInfoImage(const std::string & image_path,const SharedFD & output_file) const91 Command Avb::GenerateInfoImage(const std::string& image_path,
92                                const SharedFD& output_file) const {
93   Command command(avbtool_path_);
94   command.AddParameter(kInfoImage);
95   command.AddParameter("--image");
96   command.AddParameter(image_path);
97   command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, output_file);
98   return command;
99 }
100 
WriteInfoImage(const std::string & image_path,const std::string & output_path) const101 Result<void> Avb::WriteInfoImage(const std::string& image_path,
102                                  const std::string& output_path) const {
103   auto output_file = SharedFD::Creat(output_path, 0666);
104   CF_EXPECTF(output_file->IsOpen(), "Unable to create {} with error - {}",
105              output_path, output_file->StrError());
106   auto command = GenerateInfoImage(image_path, output_file);
107   int exit_code = command.Start().Wait();
108   CF_EXPECTF(exit_code == 0, "Failure running {} {}. Exited with status {}",
109              command.Executable(), kInfoImage, exit_code);
110   return {};
111 }
112 
GenerateMakeVbMetaImage(const std::string & output_path,const std::vector<ChainPartition> & chained_partitions,const std::vector<std::string> & included_partitions,const std::vector<std::string> & extra_arguments)113 Command Avb::GenerateMakeVbMetaImage(
114     const std::string& output_path,
115     const std::vector<ChainPartition>& chained_partitions,
116     const std::vector<std::string>& included_partitions,
117     const std::vector<std::string>& extra_arguments) {
118   Command command(avbtool_path_);
119   command.AddParameter(kMakeVbmetaImage);
120   command.AddParameter("--algorithm");
121   command.AddParameter(algorithm_);
122   command.AddParameter("--key");
123   command.AddParameter(key_);
124   command.AddParameter("--output");
125   command.AddParameter(output_path);
126 
127   for (const auto& partition : chained_partitions) {
128     const std::string argument = partition.name + ":" +
129                                  partition.rollback_index + ":" +
130                                  partition.key_path;
131     command.AddParameter("--chain_partition");
132     command.AddParameter(argument);
133   }
134   for (const auto& partition : included_partitions) {
135     command.AddParameter("--include_descriptors_from_image");
136     command.AddParameter(partition);
137   }
138   for (const auto& extra_arg : extra_arguments) {
139     command.AddParameter(extra_arg);
140   }
141   return command;
142 }
143 
MakeVbMetaImage(const std::string & output_path,const std::vector<ChainPartition> & chained_partitions,const std::vector<std::string> & included_partitions,const std::vector<std::string> & extra_arguments)144 Result<void> Avb::MakeVbMetaImage(
145     const std::string& output_path,
146     const std::vector<ChainPartition>& chained_partitions,
147     const std::vector<std::string>& included_partitions,
148     const std::vector<std::string>& extra_arguments) {
149   auto command = GenerateMakeVbMetaImage(output_path, chained_partitions,
150                                          included_partitions, extra_arguments);
151   int exit_code = command.Start().Wait();
152   CF_EXPECTF(exit_code == 0, "Failure running {} {}. Exited with status {}",
153              command.Executable(), kMakeVbmetaImage, exit_code);
154   CF_EXPECT(EnforceVbMetaSize(output_path));
155   return {};
156 }
157 
EnforceVbMetaSize(const std::string & path)158 Result<void> EnforceVbMetaSize(const std::string& path) {
159   const auto vbmeta_size = FileSize(path);
160   CF_EXPECT_LE(vbmeta_size, kVbMetaMaxSize);
161   if (vbmeta_size != kVbMetaMaxSize) {
162     auto vbmeta_fd = SharedFD::Open(path, O_RDWR);
163     CF_EXPECTF(vbmeta_fd->IsOpen(), "Unable to open {} with error {}", path,
164                vbmeta_fd->StrError());
165     CF_EXPECTF(vbmeta_fd->Truncate(kVbMetaMaxSize) == 0,
166                "Truncating {} failed with error {}", path,
167                vbmeta_fd->StrError());
168     CF_EXPECTF(vbmeta_fd->Fsync() == 0, "fsync on {} failed with error {}",
169                path, vbmeta_fd->StrError());
170   }
171   return {};
172 }
173 
GetDefaultAvb()174 std::unique_ptr<Avb> GetDefaultAvb() {
175   return std::unique_ptr<Avb>(
176       new Avb(AvbToolBinary(), kDefaultAlgorithm, TestKeyRsa4096()));
177 }
178 
CuttlefishKeyAvbComponent()179 fruit::Component<Avb> CuttlefishKeyAvbComponent() {
180   return fruit::createComponent().registerProvider(
181       []() -> Avb* { return GetDefaultAvb().release(); });
182 }
183 
184 }  // namespace cuttlefish
185