├── .gitignore ├── .travis.yml ├── Cargo.toml ├── README.md ├── build.rs ├── src ├── bin │ └── pngbox_daemon.rs ├── ffi.rs ├── lib.rs └── shim.c └── test ├── gray.png ├── mozilla-dinosaur-head-logo.png ├── rust-huge-logo.png └── servo-screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.o 3 | *.so 4 | *.dylib 5 | *.rlib 6 | *.dSYM 7 | *-test 8 | /Makefile 9 | /test_store.png 10 | /doc 11 | /target 12 | /Cargo.lock 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: false 3 | 4 | env: 5 | global: 6 | - secure: OE4AHXii7aT5oT8ruKUucrdF28rO81Y2Kl+ZRTzcT8sXs8PwpEXkle2KBCNp6lQjtP/PiuiawdDDmW9EGOoazdL4dbgx9V3wKljn+GE7s9PgGhAayKOueamFjJ3FtTOiCa9fLBlR76SsKKuqeSAcdTGS9btJGhbM71pKVqkAEZM= 7 | 8 | script: 9 | - cargo build 10 | # - cargo test 11 | 12 | after_script: 13 | - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "pngbox" 4 | version = "0.1.0" 5 | authors = ["The Servo Project Developers"] 6 | 7 | links = "png-sys" 8 | build = "build.rs" 9 | 10 | [dependencies] 11 | rustc-serialize = "0" 12 | 13 | [dependencies.png-sys] 14 | git = "https://github.com/servo/rust-png" 15 | 16 | [dependencies.urpc] 17 | git = "https://github.com/kmcallister/urpc" 18 | 19 | [dependencies.gaol] 20 | git = "https://github.com/pcwalton/gaol" 21 | 22 | [dependencies.unix_socket] 23 | git = "https://github.com/sfackler/rust-unix-socket" 24 | 25 | [build-dependencies.gcc] 26 | git = "https://github.com/alexcrichton/gcc-rs" 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Demo: OS sandboxing for unsafe libraries 2 | 3 | The [Rust][] compiler vouches only for the safety of code in the safe Rust 4 | dialect. To guard against memory exploits in a C library or `unsafe` Rust code, 5 | we have only the traditional mitigations like [ASLR][] and [no-exec stacks][]. 6 | 7 | OS-level process sandboxing would provide another, much stronger layer of 8 | protection. Setting this up traditionally requires lots of platform-specific 9 | code and complex multi-process coordination. As a result, sandboxing is used 10 | at a coarse-grained level and only in high-value targets like browsers. 11 | 12 | This repository is an early proof-of-concept that shows how sandboxing a single 13 | library could be straightforward and convenient. It runs [`libpng`][libpng] 14 | plus Servo's [very basic Rust wrapper][rust-png] in a sandboxed process, which 15 | receives compressed PNG data on a socket and replies with uncompressed data (or 16 | an error). Don't expect this to work out of the box on your machine; there are 17 | hard-coded paths among other nonsense. 18 | 19 | The sandbox setup is handled by [gaol][], which provides a high-level and 20 | cross-platform interface. The inter-process procedure calls use [urpc][] and 21 | Rust's `#[derive]` feature. All together there are about 75 lines of 22 | `libpng`-specific code, on top of Servo's non-sandboxed wrapper. I expect much 23 | of that remaining code to disappear into reusable libraries with a little more 24 | effort. Most of the action is in `src/bin/pngbox_daemon.rs`, and the 25 | implementation of `SandboxedDecoder` in `src/lib.rs`. 26 | 27 | This library's public interface is exceedingly simple. You can create a 28 | sandboxed decoder: 29 | 30 | ```rust 31 | let mut decoder = SandboxedDecoder::new(); 32 | ``` 33 | 34 | and then ask it to decode a PNG file: 35 | 36 | ```rust 37 | let pixels = try!(decoder.decode(file_contents)); 38 | ``` 39 | 40 | The security and performance of this approach has not been demonstrated! It's 41 | probably *not* fast enough for image decoding in a browser. For most image 42 | formats, a pure Rust reimplementation would be better. 43 | 44 | My top candidate for library sandboxing is [`libpurple`][libpurple], because it 45 | 46 | * has a [track record of memory-safety issues][issues], 47 | * doesn't require speedy function calls (for my purposes, anyway), and 48 | * supports a large number of features (protocols, etc.) that would be a real 49 | pain to re-implement. 50 | 51 | That's not to pick on libpurple in particular. Rather, I made this demo because 52 | I think a lot of other libraries are in the same position. 53 | 54 | The process of defining the sandbox also produces a non-sandboxed 55 | implementation with the same interface (described by a trait). It should be 56 | straightforward to write code which is generic over the choice of which 57 | particular dependencies to sandbox. This is resolved at compile time with (in 58 | theory) no added overhead in the "no sandbox" case. 59 | 60 | [ASLR]: https://en.wikipedia.org/wiki/Address_space_layout_randomization 61 | [gaol]: https://github.com/pcwalton/gaol 62 | [Rust]: http://www.rust-lang.org/ 63 | [urpc]: https://github.com/kmcallister/urpc 64 | [libpng]: http://www.libpng.org/pub/png/libpng.html 65 | [issues]: http://www.pidgin.im/news/security/ 66 | [rust-png]: https://github.com/servo/rust-png 67 | [libpurple]: http://www.pidgin.im/ 68 | [no-exec stacks]: https://en.wikipedia.org/wiki/NX_bit 69 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | #![feature(path)] 2 | 3 | extern crate gcc; 4 | 5 | use std::env; 6 | use std::path::PathBuf; 7 | 8 | fn main() { 9 | let mut cfg: gcc::Config = gcc::Config::new(); 10 | 11 | cfg.file("src/shim.c"); 12 | 13 | let src_dir = PathBuf::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join("png-sys/libpng-1.6.16"); 14 | cfg.include(&src_dir); 15 | 16 | let dep_dir = PathBuf::new(&env::var("DEP_PNG_ROOT").unwrap()); 17 | cfg.include(&dep_dir); 18 | 19 | cfg.compile("libpngshim.a") 20 | } 21 | -------------------------------------------------------------------------------- /src/bin/pngbox_daemon.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Servo Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #![crate_name = "pngbox_daemon"] 11 | #![crate_type = "bin"] 12 | 13 | #![feature(libc)] 14 | 15 | extern crate libc; 16 | extern crate urpc; 17 | extern crate gaol; 18 | extern crate pngbox; 19 | extern crate unix_socket; 20 | 21 | use std::env; 22 | use unix_socket::UnixStream; 23 | use gaol::sandbox::{ChildSandbox, ChildSandboxMethods}; 24 | use pngbox::SandboxedDecoder; 25 | 26 | pub fn main() { 27 | let stream = UnixStream::from_fd(env::args() 28 | .skip(1).next().unwrap() 29 | .parse().unwrap()); 30 | 31 | let profile = SandboxedDecoder::profile(); 32 | ChildSandbox::new(profile).activate().unwrap(); 33 | 34 | pngbox::png::serve(pngbox::LocalDecoder, stream).unwrap(); 35 | } 36 | -------------------------------------------------------------------------------- /src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #![allow(non_camel_case_types, dead_code)] 11 | 12 | use libc::{c_int, size_t, c_void, c_char}; 13 | 14 | pub const TRANSFORM_IDENTITY: c_int = 0; 15 | 16 | pub const FILTER_NONE: c_int = 0; 17 | 18 | pub const INTERLACE_NONE: c_int = 0; 19 | 20 | pub const COMPRESSION_TYPE_DEFAULT: c_int = 0; 21 | 22 | pub const COLOR_TYPE_GRAY: c_int = 0; 23 | pub const COLOR_TYPE_RGB: c_int = 2; 24 | pub const COLOR_TYPE_PALETTE: c_int = 3; 25 | pub const COLOR_TYPE_GRAY_ALPHA: c_int = 4; 26 | pub const COLOR_TYPE_GA: c_int = 4; 27 | pub const COLOR_TYPE_RGB_ALPHA: c_int = 6; 28 | pub const COLOR_TYPE_RGBA: c_int = 6; 29 | 30 | pub const FILLER_AFTER: c_int = 1; 31 | #[allow(non_upper_case_globals)] 32 | pub const INFO_tRNS: c_int = 0x0010; 33 | 34 | pub type png_struct = c_void; 35 | pub type png_info = c_void; 36 | 37 | #[link(name = "z")] 38 | #[link(name = "png16", kind = "static")] 39 | extern { 40 | // libc routines needed 41 | pub fn setjmp(env: *mut c_void) -> c_int; 42 | 43 | // shim routines 44 | pub fn pngshim_jmpbuf(pnt_ptr: *mut png_struct) -> *mut c_void; 45 | 46 | // libpng routines 47 | pub fn RUST_png_get_header_ver(png_ptr: *mut png_struct) -> *mut c_char; 48 | pub fn RUST_png_sig_cmp(sig: *const u8, start: size_t, num_to_check: size_t) -> c_int; 49 | 50 | pub fn RUST_png_create_info_struct(png_ptr: *mut png_struct) -> *mut png_info; 51 | pub fn RUST_png_get_io_ptr(png_ptr: *mut png_struct) -> *mut c_void; 52 | pub fn RUST_png_set_sig_bytes(png_ptr: *mut png_struct, num_bytes: c_int); 53 | 54 | pub fn RUST_png_create_read_struct(user_png_ver: *const c_char, error_ptr: *mut c_void, error_fn: *mut u8, warn_fn: *mut u8) -> *mut png_struct; 55 | pub fn RUST_png_destroy_read_struct(png_ptr_ptr: *mut *mut png_struct, info_ptr_ptr: *mut *mut png_info, end_info_ptr_ptr: *mut *mut png_info); 56 | pub fn RUST_png_set_read_fn(png_ptr: *mut png_struct, io_ptr: *mut c_void, read_data_fn: extern "C" fn(*mut png_struct, *mut u8, size_t)); 57 | pub fn RUST_png_read_info(png_ptr: *mut png_struct, info_ptr: *mut png_info); 58 | pub fn RUST_png_read_update_info(png_ptr: *mut png_struct, info_ptr: *mut png_info); 59 | pub fn RUST_png_read_image(png_ptr: *mut png_struct, row_pointers: *mut *mut u8); 60 | pub fn RUST_png_read_png(png_ptr: *mut png_struct, info_ptr: *mut png_info, transforms: c_int, params: *mut c_void); 61 | 62 | pub fn RUST_png_create_write_struct(user_png_ver: *const c_char, error_ptr: *mut c_void, error_fn: *mut u8, warn_fn: *mut u8) -> *mut png_struct; 63 | pub fn RUST_png_destroy_write_struct(png_ptr_ptr: *mut *mut png_struct, info_ptr_ptr: *mut *mut png_info); 64 | pub fn RUST_png_set_write_fn(png_ptr: *mut png_struct, io_ptr: *mut c_void, write_data_fn: extern "C" fn(*mut png_struct, *mut u8, size_t), output_flush_ptr: extern "C" fn(*mut png_struct)); 65 | pub fn RUST_png_write_png(pnt_ptr: *mut png_struct, info_ptr: *mut png_info, transforms: c_int, params: *mut c_void); // ?? 66 | 67 | pub fn RUST_png_get_IHDR(png_ptr: *mut png_struct, info_ptr: *mut png_info, width: *mut u32, height: *mut u32, bit_depth: *mut c_int, color_type: *mut c_int, interlace_method: *mut c_int, compression_method: *mut c_int, filter_method: *mut c_int) -> u32; 68 | pub fn RUST_png_get_pHYs(png_ptr: *mut png_struct, info_ptr: *mut png_info, res_x: *mut u32, res_y: *mut u32, unit_type: *mut c_int) -> u32; 69 | pub fn RUST_png_get_image_width(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> u32; 70 | pub fn RUST_png_get_image_height(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> u32; 71 | pub fn RUST_png_get_bit_depth(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> u8; 72 | pub fn RUST_png_get_color_type(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> u8; 73 | pub fn RUST_png_get_valid(png_ptr: *mut png_struct, info_ptr: *mut png_info, flag: u32) -> u32; 74 | pub fn RUST_png_get_rows(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> *mut *mut u8; 75 | 76 | pub fn RUST_png_set_IHDR(png_ptr: *mut png_struct, info_ptr: *mut png_info, width: u32, height: u32, bit_depth: c_int, color_type: c_int, interlace_method: c_int, compression_method: c_int, filter_method: c_int); 77 | pub fn RUST_png_set_pHYs(png_ptr: *mut png_struct, info_ptr: *mut png_info, res_x: u32, res_y: u32, unit_type: c_int); 78 | pub fn RUST_png_set_rows(png_ptr: *mut png_struct, info_ptr: *mut png_info, row_pointers: *mut *mut u8); 79 | 80 | pub fn RUST_png_set_packing(png_ptr: *mut png_struct); 81 | pub fn RUST_png_set_palette_to_rgb(png_ptr: *mut png_struct); 82 | pub fn RUST_png_set_expand_gray_1_2_4_to_8(png_ptr: *mut png_struct); 83 | pub fn RUST_png_set_gray_to_rgb(png_ptr: *mut png_struct); 84 | pub fn RUST_png_set_tRNS_to_alpha(png_ptr: *mut png_struct); 85 | pub fn RUST_png_set_add_alpha(png_ptr: *mut png_struct, val: u32, flag: c_int); 86 | pub fn RUST_png_set_filler(png_ptr: *mut png_struct, val: u32, flag: c_int); 87 | pub fn RUST_png_set_interlace_handling(png_ptr: *mut png_struct); 88 | pub fn RUST_png_set_strip_16(png_ptr: *mut png_struct); 89 | } 90 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #![crate_name = "pngbox"] 11 | #![crate_type = "lib"] 12 | 13 | #![allow(unused_features)] 14 | #![feature(core, libc, test, std_misc, old_io, old_path, io)] 15 | 16 | extern crate libc; 17 | extern crate "rustc-serialize" as rustc_serialize; 18 | extern crate unix_socket; 19 | extern crate gaol; 20 | extern crate "test" as rust_test; 21 | 22 | #[macro_use] 23 | extern crate urpc; 24 | 25 | use libc::{c_int, size_t}; 26 | use std::{mem, ptr, slice}; 27 | use std::ops::{Deref, DerefMut}; 28 | use std::iter::repeat; 29 | use std::os::unix::AsRawFd; 30 | use unix_socket::UnixStream; 31 | use gaol::profile::Profile; 32 | use gaol::sandbox::{Sandbox, SandboxMethods, Command}; 33 | 34 | mod ffi; 35 | 36 | #[derive(PartialEq, Eq, RustcEncodable, RustcDecodable)] 37 | pub enum PixelsByColorType { 38 | K8(Vec), 39 | KA8(Vec), 40 | RGB8(Vec), 41 | RGBA8(Vec), 42 | } 43 | 44 | #[derive(PartialEq, Eq, RustcEncodable, RustcDecodable)] 45 | pub struct Image { 46 | pub width: u32, 47 | pub height: u32, 48 | pub pixels: PixelsByColorType, 49 | } 50 | 51 | #[derive(PartialEq, Eq, RustcEncodable, RustcDecodable)] 52 | pub enum DecodeResult { 53 | Image(Image), 54 | Error(String), 55 | } 56 | 57 | urpc! { 58 | pub interface png { 59 | fn decode(compressed: Vec) -> ::DecodeResult { } 60 | } 61 | } 62 | 63 | pub struct LocalDecoder; 64 | 65 | impl png::Methods for LocalDecoder { 66 | fn decode(&mut self, compressed: Vec) -> urpc::Result { 67 | Ok(decode_from_memory(&compressed)) 68 | } 69 | } 70 | 71 | pub struct SandboxedDecoder(png::Client); 72 | 73 | impl Deref for SandboxedDecoder { 74 | type Target = png::Client; 75 | fn deref(&self) -> &png::Client { &self.0 } 76 | } 77 | 78 | impl DerefMut for SandboxedDecoder { 79 | fn deref_mut(&mut self) -> &mut png::Client { &mut self.0 } 80 | } 81 | 82 | impl SandboxedDecoder { 83 | pub fn profile() -> Profile { 84 | // No operations allowed. 85 | Profile::new(vec![]).unwrap() 86 | } 87 | 88 | pub fn new() -> SandboxedDecoder { 89 | let [s1, s2] = UnixStream::unnamed().unwrap(); 90 | let mut command = Command::new(b"/home/keegan/pngbox/target/pngbox_daemon"); 91 | command.arg(&format!("{}", s1.as_raw_fd())); 92 | let profile = SandboxedDecoder::profile(); 93 | Sandbox::new(profile).start(&mut command).unwrap(); 94 | 95 | SandboxedDecoder(png::Client::new(s2)) 96 | } 97 | } 98 | 99 | // This intermediate data structure is used to read 100 | // an image data from 'offset' position, and store it 101 | // to the data vector. 102 | struct ImageData<'a> { 103 | data: &'a [u8], 104 | offset: usize, 105 | } 106 | 107 | extern "C" fn read_data(png_ptr: *mut ffi::png_struct, data: *mut u8, length: size_t) { 108 | unsafe { 109 | let io_ptr = ffi::RUST_png_get_io_ptr(png_ptr); 110 | let image_data: &mut ImageData = mem::transmute(io_ptr); 111 | let len = length as usize; 112 | let buf = slice::from_raw_parts_mut(data, len); 113 | let end_pos = std::cmp::min(image_data.data.len()-image_data.offset, len); 114 | let src = &image_data.data[image_data.offset..image_data.offset+end_pos]; 115 | 116 | ptr::copy(buf.as_mut_ptr(), src.as_ptr(), src.len()); 117 | image_data.offset += end_pos; 118 | } 119 | } 120 | 121 | fn decode_from_memory(image: &[u8]) -> DecodeResult { 122 | unsafe { 123 | let mut png_ptr = ffi::RUST_png_create_read_struct(&*ffi::RUST_png_get_header_ver(ptr::null_mut()), 124 | ptr::null_mut(), 125 | ptr::null_mut(), 126 | ptr::null_mut()); 127 | if png_ptr.is_null() { 128 | return DecodeResult::Error("could not create read struct".to_string()); 129 | } 130 | let mut info_ptr = ffi::RUST_png_create_info_struct(png_ptr); 131 | if info_ptr.is_null() { 132 | ffi::RUST_png_destroy_read_struct(&mut png_ptr, ptr::null_mut(), ptr::null_mut()); 133 | return DecodeResult::Error("could not create info struct".to_string()); 134 | } 135 | let res = ffi::setjmp(ffi::pngshim_jmpbuf(png_ptr)); 136 | if res != 0 { 137 | ffi::RUST_png_destroy_read_struct(&mut png_ptr, &mut info_ptr, ptr::null_mut()); 138 | return DecodeResult::Error("error reading png".to_string()); 139 | } 140 | 141 | let mut image_data = ImageData { 142 | data: image, 143 | offset: 0, 144 | }; 145 | 146 | ffi::RUST_png_set_read_fn(png_ptr, mem::transmute(&mut image_data), read_data); 147 | ffi::RUST_png_read_info(png_ptr, info_ptr); 148 | 149 | let width = ffi::RUST_png_get_image_width(png_ptr, info_ptr) as usize; 150 | let height = ffi::RUST_png_get_image_height(png_ptr, info_ptr) as usize; 151 | let color_type = ffi::RUST_png_get_color_type(png_ptr, info_ptr); 152 | let bit_depth = ffi::RUST_png_get_bit_depth(png_ptr, info_ptr); 153 | 154 | // convert palette and grayscale to rgb 155 | match color_type as c_int { 156 | ffi::COLOR_TYPE_PALETTE => { 157 | ffi::RUST_png_set_palette_to_rgb(png_ptr); 158 | } 159 | ffi::COLOR_TYPE_GRAY | ffi::COLOR_TYPE_GRAY_ALPHA => { 160 | ffi::RUST_png_set_gray_to_rgb(png_ptr); 161 | } 162 | _ => {} 163 | } 164 | 165 | // convert 16-bit channels to 8-bit 166 | if bit_depth == 16 { 167 | ffi::RUST_png_set_strip_16(png_ptr); 168 | } 169 | 170 | // add alpha channels 171 | ffi::RUST_png_set_add_alpha(png_ptr, 0xff, ffi::FILLER_AFTER); 172 | if ffi::RUST_png_get_valid(png_ptr, info_ptr, ffi::INFO_tRNS as u32) != 0 { 173 | ffi::RUST_png_set_tRNS_to_alpha(png_ptr); 174 | } 175 | 176 | ffi::RUST_png_set_packing(png_ptr); 177 | ffi::RUST_png_set_interlace_handling(png_ptr); 178 | ffi::RUST_png_read_update_info(png_ptr, info_ptr); 179 | 180 | let updated_bit_depth = ffi::RUST_png_get_bit_depth(png_ptr, info_ptr); 181 | let updated_color_type = ffi::RUST_png_get_color_type(png_ptr, info_ptr); 182 | 183 | let (color_type, pixel_width) = match (updated_color_type as c_int, updated_bit_depth) { 184 | (ffi::COLOR_TYPE_RGB, 8) | 185 | (ffi::COLOR_TYPE_RGBA, 8) | 186 | (ffi::COLOR_TYPE_PALETTE, 8) => (PixelsByColorType::RGBA8 as fn(Vec) -> PixelsByColorType, 4usize), 187 | (ffi::COLOR_TYPE_GRAY, 8) => (PixelsByColorType::K8 as fn(Vec) -> PixelsByColorType, 1usize), 188 | (ffi::COLOR_TYPE_GA, 8) => (PixelsByColorType::KA8 as fn(Vec) -> PixelsByColorType, 2usize), 189 | _ => panic!("color type not supported"), 190 | }; 191 | 192 | let mut image_data: Vec = repeat(0u8).take(width * height * pixel_width).collect(); 193 | let image_buf = image_data.as_mut_ptr(); 194 | let mut row_pointers: Vec<*mut u8> = (0..height).map(|idx| { 195 | image_buf.offset((width * pixel_width * idx) as isize) 196 | }).collect(); 197 | 198 | ffi::RUST_png_read_image(png_ptr, row_pointers.as_mut_ptr()); 199 | 200 | ffi::RUST_png_destroy_read_struct(&mut png_ptr, &mut info_ptr, ptr::null_mut()); 201 | 202 | DecodeResult::Image(Image { 203 | width: width as u32, 204 | height: height as u32, 205 | pixels: color_type(image_data), 206 | }) 207 | } 208 | } 209 | 210 | #[cfg(test)] 211 | mod test { 212 | use std::old_io::File; 213 | use super::{DecodeResult, LocalDecoder, SandboxedDecoder}; 214 | use super::PixelsByColorType::RGBA8; 215 | use rust_test::Bencher; 216 | 217 | fn load_rgba8(decoder: &mut D, file: &'static str, w: u32, h: u32) -> Vec 218 | where D: super::png::Methods, 219 | { 220 | let contents = File::open(&Path::new(file)).read_to_end().unwrap(); 221 | match decoder.decode(contents).unwrap() { 222 | DecodeResult::Error(m) => panic!(m), 223 | DecodeResult::Image(image) => { 224 | assert_eq!(image.width, w); 225 | assert_eq!(image.height, h); 226 | match image.pixels { 227 | RGBA8(px) => px, 228 | _ => panic!("Expected RGBA8") 229 | } 230 | } 231 | } 232 | } 233 | 234 | #[test] 235 | fn test_sandboxed() { 236 | let mut d = SandboxedDecoder::new(); 237 | 238 | assert_eq!(load_rgba8(&mut *d, "test/servo-screenshot.png", 831, 624), 239 | load_rgba8(&mut LocalDecoder, "test/servo-screenshot.png", 831, 624)); 240 | 241 | assert_eq!(load_rgba8(&mut *d, "test/gray.png", 100, 100), 242 | load_rgba8(&mut LocalDecoder, "test/gray.png", 100, 100)); 243 | } 244 | 245 | #[bench] 246 | fn bench_local(bh: &mut Bencher) { 247 | use super::png::Methods; 248 | 249 | let contents = File::open(&Path::new("test/servo-screenshot.png")) 250 | .read_to_end().unwrap(); 251 | bh.iter(|| { 252 | assert!(LocalDecoder.decode(contents.clone()).is_ok()); 253 | }); 254 | } 255 | 256 | #[bench] 257 | fn bench_sandboxed(bh: &mut Bencher) { 258 | use super::png::Methods; 259 | 260 | let mut decoder = SandboxedDecoder::new(); 261 | let contents = File::open(&Path::new("test/servo-screenshot.png")) 262 | .read_to_end().unwrap(); 263 | bh.iter(|| { 264 | assert!(decoder.decode(contents.clone()).is_ok()); 265 | }); 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /src/shim.c: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #include 6 | 7 | jmp_buf *pngshim_jmpbuf(png_struct *png_ptr) { 8 | return &png_jmpbuf(png_ptr); 9 | } 10 | -------------------------------------------------------------------------------- /test/gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmcallister/pngbox/e2fd6d214a45f55fca0427fd52d683861aae09ac/test/gray.png -------------------------------------------------------------------------------- /test/mozilla-dinosaur-head-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmcallister/pngbox/e2fd6d214a45f55fca0427fd52d683861aae09ac/test/mozilla-dinosaur-head-logo.png -------------------------------------------------------------------------------- /test/rust-huge-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmcallister/pngbox/e2fd6d214a45f55fca0427fd52d683861aae09ac/test/rust-huge-logo.png -------------------------------------------------------------------------------- /test/servo-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmcallister/pngbox/e2fd6d214a45f55fca0427fd52d683861aae09ac/test/servo-screenshot.png --------------------------------------------------------------------------------