use cstr crate rather than unsafe

This removes a few uses of unsafe, and it verifies statically that there
are no interior NUL bytes.
This commit is contained in:
Scott Lamb 2019-07-04 16:51:38 -05:00
parent 06d7815f9c
commit 13b192949d
5 changed files with 40 additions and 16 deletions

28
Cargo.lock generated
View File

@ -287,6 +287,24 @@ dependencies = [
"subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cstr"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cstr-macros 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cstr-macros"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cursive"
version = "0.12.0"
@ -941,6 +959,7 @@ version = "0.0.1"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"cstr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -981,6 +1000,7 @@ dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"cstr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cursive 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1296,6 +1316,11 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "procedural-masquerade"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "protobuf"
version = "3.0.0-pre"
@ -2370,6 +2395,8 @@ dependencies = [
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
"checksum cstr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "19f7a08ed4ecd7e077d4cee63937473e6f7cf57b702a9114ef41751b2cbc0f60"
"checksum cstr-macros 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0f12dd847ec773fc98d75edba5394cb87d0f35e7ee548a4c81849ca6374b3d48"
"checksum cursive 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7ecc7282b5361471b607c26f44148205607e26d48a2fc65bd16e7619b1ebb78"
"checksum darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfbcb0c5961907597a7d1148e3af036268f2b773886b8bb3eeb1e1281d3d3d6"
"checksum darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6afc018370c3bff3eb51f89256a6bdb18b4fdcda72d577982a14954a7a0b402c"
@ -2472,6 +2499,7 @@ dependencies = [
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1574a51c3fd37b26d2c0032b649d08a7d51d4cca9c41bbc5bf7118fa4509d0"
"checksum protobuf 3.0.0-pre (git+https://github.com/stepancheg/rust-protobuf)" = "<none>"
"checksum protobuf-codegen 3.0.0-pre (git+https://github.com/stepancheg/rust-protobuf)" = "<none>"
"checksum protobuf-codegen-pure 3.0.0-pre (git+https://github.com/stepancheg/rust-protobuf)" = "<none>"

View File

@ -22,6 +22,7 @@ base = { package = "moonfire-base", path = "base" }
base64 = "0.10.0"
bytes = "0.4.6"
byteorder = "1.0"
cstr = "0.1.7"
cursive = "0.12"
db = { package = "moonfire-db", path = "db" }
docopt = "1.0"

View File

@ -15,6 +15,7 @@ path = "lib.rs"
base = { package = "moonfire-base", path = "../base" }
base64 = "0.10.0"
blake2-rfc = "0.2.18"
cstr = "0.1.7"
failure = "0.1.1"
fnv = "1.0"
lazy_static = "1.0"

View File

@ -33,6 +33,7 @@
//! This includes opening files for serving, rotating away old files, and saving new files.
use crate::db::CompositeId;
use cstr::*;
use failure::{Error, Fail, bail, format_err};
use libc::c_char;
use log::warn;
@ -140,7 +141,7 @@ pub(crate) unsafe fn renameat(from_fd: &Fd, from_path: *const c_char,
/// Reads `dir`'s metadata. If none is found, returns an empty proto.
pub(crate) fn read_meta(dir: &Fd) -> Result<schema::DirMeta, Error> {
let mut meta = schema::DirMeta::default();
let p = unsafe { ffi::CStr::from_ptr("meta\0".as_ptr() as *const c_char) };
let p = cstr!("meta");
let mut f = match unsafe { dir.openat(p.as_ptr(), libc::O_RDONLY, 0) } {
Err(e) => {
if e.kind() == ::std::io::ErrorKind::NotFound {
@ -159,10 +160,8 @@ pub(crate) fn read_meta(dir: &Fd) -> Result<schema::DirMeta, Error> {
/// Write `dir`'s metadata, clobbering existing data.
pub(crate) fn write_meta(dir: &Fd, meta: &schema::DirMeta) -> Result<(), Error> {
let (tmp_path, final_path) = unsafe {
(ffi::CStr::from_ptr("meta.tmp\0".as_ptr() as *const c_char),
ffi::CStr::from_ptr("meta\0".as_ptr() as *const c_char))
};
let tmp_path = cstr!("meta.tmp");
let final_path = cstr!("meta");
let mut f = unsafe { dir.openat(tmp_path.as_ptr(),
libc::O_CREAT | libc::O_TRUNC | libc::O_WRONLY, 0o600)? };
meta.write_to_writer(&mut f)?;

View File

@ -29,6 +29,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use crate::h264;
use cstr::*;
use failure::{Error, bail};
use ffmpeg;
use lazy_static::lazy_static;
@ -78,12 +79,6 @@ impl Ffmpeg {
}
}
macro_rules! c_str {
($s:expr) => { {
unsafe { CStr::from_ptr(concat!($s, "\0").as_ptr() as *const c_char) }
} }
}
impl Opener<FfmpegStream> for Ffmpeg {
fn open(&self, src: Source) -> Result<FfmpegStream, Error> {
use ffmpeg::InputFormatContext;
@ -93,7 +88,7 @@ impl Opener<FfmpegStream> for Ffmpeg {
let mut open_options = ffmpeg::Dictionary::new();
// Work around https://github.com/scottlamb/moonfire-nvr/issues/10
open_options.set(c_str!("advanced_editlist"), c_str!("false")).unwrap();
open_options.set(cstr!("advanced_editlist"), cstr!("false")).unwrap();
let url = format!("file:{}", filename);
let i = InputFormatContext::open(&CString::new(url.clone()).unwrap(),
&mut open_options)?;
@ -105,14 +100,14 @@ impl Opener<FfmpegStream> for Ffmpeg {
}
Source::Rtsp{url, redacted_url} => {
let mut open_options = ffmpeg::Dictionary::new();
open_options.set(c_str!("rtsp_transport"), c_str!("tcp")).unwrap();
open_options.set(c_str!("user-agent"), c_str!("moonfire-nvr")).unwrap();
open_options.set(cstr!("rtsp_transport"), cstr!("tcp")).unwrap();
open_options.set(cstr!("user-agent"), cstr!("moonfire-nvr")).unwrap();
// 10-second socket timeout, in microseconds.
open_options.set(c_str!("stimeout"), c_str!("10000000")).unwrap();
open_options.set(cstr!("stimeout"), cstr!("10000000")).unwrap();
// Moonfire NVR currently only supports video, so receiving audio is wasteful.
// It also triggers <https://github.com/scottlamb/moonfire-nvr/issues/36>.
open_options.set(c_str!("allowed_media_types"), c_str!("video")).unwrap();
open_options.set(cstr!("allowed_media_types"), cstr!("video")).unwrap();
let i = InputFormatContext::open(&CString::new(url).unwrap(), &mut open_options)?;
if !open_options.empty() {