• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <fcntl.h>
16 #include <unistd.h>
17 
18 #include "../sandboxed.h"     // NOLINT(build/include)
19 #include "../tests/libpng.h"  // NOLINT(build/include)
20 
21 struct Data {
22   int width;
23   int height;
24   uint8_t color_type;
25   uint8_t bit_depth;
26   int number_of_passes;
27   size_t rowbytes;
28   std::unique_ptr<sapi::v::Array<uint8_t>> row_pointers;
29 };
30 
ReadPng(LibPNGApi & api,absl::string_view infile)31 absl::StatusOr<Data> ReadPng(LibPNGApi& api, absl::string_view infile) {
32   sapi::v::Fd fd(open(infile.data(), O_RDONLY));
33 
34   if (fd.GetValue() < 0) {
35     return absl::InternalError("Error opening input file");
36   }
37 
38   SAPI_RETURN_IF_ERROR((&api)->sandbox()->TransferToSandboxee(&fd));
39 
40   if (fd.GetRemoteFd() < 0) {
41     return absl::InternalError("Error receiving remote FD");
42   }
43 
44   absl::StatusOr<void*> status_or_file;
45   sapi::v::ConstCStr rb_var("rb");
46   SAPI_ASSIGN_OR_RETURN(status_or_file,
47                         api.png_fdopen(fd.GetRemoteFd(), rb_var.PtrBefore()));
48 
49   sapi::v::RemotePtr file(status_or_file.value());
50   if (!file.GetValue()) {
51     return absl::InternalError(absl::StrCat("Could not open ", infile));
52   }
53 
54   sapi::v::Array<char> header(8);
55   SAPI_RETURN_IF_ERROR(
56       api.png_fread(header.PtrBoth(), 1, header.GetSize(), &file));
57 
58   SAPI_ASSIGN_OR_RETURN(int return_value,
59                         api.png_sig_cmp(header.PtrBoth(), 0, header.GetSize()));
60   if (return_value != 0) {
61     return absl::InternalError(absl::StrCat(infile, " is not a PNG file"));
62   }
63 
64   absl::StatusOr<png_structp> status_or_png_structp;
65   sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING);
66   SAPI_ASSIGN_OR_RETURN(
67       status_or_png_structp,
68       api.png_create_read_struct_wrapper(ver_string_var.PtrBefore(), nullptr));
69 
70   sapi::v::RemotePtr struct_ptr(status_or_png_structp.value());
71   if (!struct_ptr.GetValue()) {
72     return absl::InternalError("png_create_read_struct_wrapper failed");
73   }
74 
75   absl::StatusOr<png_infop> status_or_png_infop;
76   SAPI_ASSIGN_OR_RETURN(status_or_png_infop,
77                         api.png_create_info_struct(&struct_ptr));
78 
79   sapi::v::RemotePtr info_ptr(status_or_png_infop.value());
80   if (!info_ptr.GetValue()) {
81     return absl::InternalError("png_create_info_struct failed");
82   }
83 
84   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
85   SAPI_RETURN_IF_ERROR(api.png_init_io_wrapper(&struct_ptr, &file));
86   SAPI_RETURN_IF_ERROR(api.png_set_sig_bytes(&struct_ptr, header.GetSize()));
87   SAPI_RETURN_IF_ERROR(api.png_read_info(&struct_ptr, &info_ptr));
88 
89   Data data;
90   SAPI_ASSIGN_OR_RETURN(data.width,
91                         api.png_get_image_width(&struct_ptr, &info_ptr));
92 
93   SAPI_ASSIGN_OR_RETURN(data.height,
94                         api.png_get_image_height(&struct_ptr, &info_ptr));
95 
96   SAPI_ASSIGN_OR_RETURN(data.color_type,
97                         api.png_get_color_type(&struct_ptr, &info_ptr));
98 
99   SAPI_ASSIGN_OR_RETURN(data.bit_depth,
100                         api.png_get_bit_depth(&struct_ptr, &info_ptr));
101 
102   SAPI_ASSIGN_OR_RETURN(data.number_of_passes,
103                         api.png_set_interlace_handling(&struct_ptr));
104 
105   SAPI_RETURN_IF_ERROR(api.png_read_update_info(&struct_ptr, &info_ptr));
106   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
107 
108   SAPI_ASSIGN_OR_RETURN(data.rowbytes,
109                         api.png_get_rowbytes(&struct_ptr, &info_ptr));
110   data.row_pointers =
111       std::make_unique<sapi::v::Array<uint8_t>>(data.height * data.rowbytes);
112 
113   SAPI_RETURN_IF_ERROR(api.png_read_image_wrapper(
114       &struct_ptr, data.row_pointers->PtrAfter(), data.height, data.rowbytes));
115 
116   SAPI_RETURN_IF_ERROR(api.png_fclose(&file));
117   return data;
118 }
119 
WritePng(LibPNGApi & api,absl::string_view outfile,Data & data)120 absl::Status WritePng(LibPNGApi& api, absl::string_view outfile, Data& data) {
121   sapi::v::Fd fd(open(outfile.data(), O_WRONLY));
122   if (fd.GetValue() < 0) {
123     return absl::InternalError("Error opening output file");
124   }
125 
126   SAPI_RETURN_IF_ERROR((&api)->sandbox()->TransferToSandboxee(&fd));
127   if (fd.GetRemoteFd() < 0) {
128     return absl::InternalError("Error receiving remote FD");
129   }
130 
131   absl::StatusOr<void*> status_or_file;
132   sapi::v::ConstCStr wb_var("wb");
133   SAPI_ASSIGN_OR_RETURN(status_or_file,
134                         api.png_fdopen(fd.GetRemoteFd(), wb_var.PtrBefore()));
135 
136   sapi::v::RemotePtr file(status_or_file.value());
137   if (!file.GetValue()) {
138     return absl::InternalError(absl::StrCat("Could not open ", outfile));
139   }
140 
141   absl::StatusOr<png_structp> status_or_png_structp;
142   sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING);
143   SAPI_ASSIGN_OR_RETURN(
144       status_or_png_structp,
145       api.png_create_write_struct_wrapper(ver_string_var.PtrBefore(), nullptr));
146 
147   sapi::v::RemotePtr struct_ptr(status_or_png_structp.value());
148   if (!struct_ptr.GetValue()) {
149     return absl::InternalError("png_create_write_struct_wrapper failed");
150   }
151 
152   absl::StatusOr<png_infop> status_or_png_infop;
153   SAPI_ASSIGN_OR_RETURN(status_or_png_infop,
154                         api.png_create_info_struct(&struct_ptr));
155 
156   sapi::v::RemotePtr info_ptr(status_or_png_infop.value());
157   if (!info_ptr.GetValue()) {
158     return absl::InternalError("png_create_info_struct failed");
159   }
160 
161   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
162   SAPI_RETURN_IF_ERROR(api.png_init_io_wrapper(&struct_ptr, &file));
163 
164   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
165   SAPI_RETURN_IF_ERROR(
166       api.png_set_IHDR(&struct_ptr, &info_ptr, data.width, data.height,
167                        data.bit_depth, data.color_type, PNG_INTERLACE_NONE,
168                        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE));
169 
170   SAPI_RETURN_IF_ERROR(api.png_write_info(&struct_ptr, &info_ptr));
171 
172   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
173   SAPI_RETURN_IF_ERROR(api.png_write_image_wrapper(
174       &struct_ptr, data.row_pointers->PtrBefore(), data.height, data.rowbytes));
175 
176   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
177   SAPI_RETURN_IF_ERROR(api.png_write_end(&struct_ptr, nullptr));
178 
179   SAPI_RETURN_IF_ERROR(api.png_fclose(&file));
180   return absl::OkStatus();
181 }
182 
LibPNGMain(const std::string & infile,const std::string & outfile)183 absl::Status LibPNGMain(const std::string& infile, const std::string& outfile) {
184   LibPNGSapiSandbox sandbox;
185   sandbox.AddFile(infile);
186   sandbox.AddFile(outfile);
187 
188   SAPI_RETURN_IF_ERROR(sandbox.Init());
189   LibPNGApi api(&sandbox);
190 
191   SAPI_ASSIGN_OR_RETURN(Data data, ReadPng(api, infile));
192 
193   if (data.color_type != PNG_COLOR_TYPE_RGBA &&
194       data.color_type != PNG_COLOR_TYPE_RGB) {
195     return absl::InternalError(absl::StrCat(
196         infile, " has unexpected color type. Expected RGB or RGBA"));
197   }
198 
199   size_t channel_count = 3;
200   if (data.color_type == PNG_COLOR_TYPE_RGBA) {
201     channel_count = 4;
202   }
203 
204   // RGB to BGR
205   for (size_t i = 0; i != data.height; ++i) {
206     for (size_t j = 0; j != data.width; ++j) {
207       uint8_t r = (*data.row_pointers)[i * data.rowbytes + j * channel_count];
208       uint8_t g =
209           (*data.row_pointers)[i * data.rowbytes + j * channel_count + 1];
210       uint8_t b =
211           (*data.row_pointers)[i * data.rowbytes + j * channel_count + 2];
212       (*data.row_pointers)[i * data.rowbytes + j * channel_count] = b;
213       (*data.row_pointers)[i * data.rowbytes + j * channel_count + 2] = r;
214     }
215   }
216 
217   SAPI_RETURN_IF_ERROR(WritePng(api, outfile, data));
218   return absl::OkStatus();
219 }
220 
main(int argc,char * argv[])221 int main(int argc, char* argv[]) {
222   if (argc != 3) {
223     LOG(ERROR) << "Usage: example5 infile outfile";
224     return EXIT_FAILURE;
225   }
226 
227   auto status = LibPNGMain(argv[1], argv[2]);
228   if (!status.ok()) {
229     LOG(ERROR) << "LibPNGMain failed with error:\n"
230                << status.ToString() << '\n';
231     return EXIT_FAILURE;
232   }
233 
234   return EXIT_SUCCESS;
235 }
236