From c7c71c725b48a1ea14bfae76927fb6781c149aab Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 12:49:35 -0600 Subject: [PATCH] libopenbsd(3): adds pledge(2) and unveil(2) support for Rust; Makefile, include: adds conditional compilation --- Makefile | 15 +++++--- include/FreeBSD.mk | 6 ++++ include/Linux.mk | 6 ++++ include/OpenBSD.mk | 13 +++++++ src/libopenbsd.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 include/FreeBSD.mk create mode 100644 include/Linux.mk create mode 100644 include/OpenBSD.mk create mode 100644 src/libopenbsd.rs diff --git a/Makefile b/Makefile index 87bf566..0a9a4fe 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,9 @@ DESTDIR ?= dist PREFIX ?= /usr/local +# for conditionally compiling OS features +OS != uname + # normalized prefix PREFIX_N != dirname $(PREFIX)/. MANDIR != test $(PREFIX_N) = / && printf '/usr/share/man\n' \ @@ -26,8 +29,8 @@ SYSEXITS != printf '\043include \n' | cpp -M - | tr ' ' '\n' \ CC ?= cc RUSTC ?= rustc RUSTFLAGS += --extern getopt=build/o/libgetopt.rlib \ - --extern sysexits=build/o/libsysexits.rlib \ - --extern strerror=build/o/libstrerror.rlib + --extern strerror=build/o/libstrerror.rlib \ + --extern sysexits=build/o/libsysexits.rlib CFLAGS += -I$(SYSEXITS) # testing requires the absolute path to the bin directory set @@ -74,9 +77,13 @@ docs: docs/ build "s/X\.X\.X/$$(git describe --tags --long | cut -d'-' -f1)/g")"; \ sed "s/$$original/$$title/g" <"$$file" >"build/$$file"; done + +# include OS feature libraries for compilation +include include/$(OS).mk + .PHONY: rustlibs -rustlibs: build/o/libsysexits.rlib build/o/libgetopt.rlib \ - build/o/libstrerror.rlib +rustlibs: build/o/libgetopt.rlib build/o/libstrerror.rlib \ + build/o/libsysexits.rlib $(OSLIB) build/o/libgetopt.rlib: build src/libgetopt.rs $(RUSTC) $(RUSTFLAGS) --crate-type=lib --crate-name=getopt \ diff --git a/include/FreeBSD.mk b/include/FreeBSD.mk new file mode 100644 index 0000000..8d679b4 --- /dev/null +++ b/include/FreeBSD.mk @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. diff --git a/include/Linux.mk b/include/Linux.mk new file mode 100644 index 0000000..8d679b4 --- /dev/null +++ b/include/Linux.mk @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. diff --git a/include/OpenBSD.mk b/include/OpenBSD.mk new file mode 100644 index 0000000..9624629 --- /dev/null +++ b/include/OpenBSD.mk @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +OSLIB = build/o/libopenbsd.rlib +RUSTFLAGS += --extern openbsd=$(OSLIB) + +$(OSLIB): src/libopenbsd.rs + $(RUSTC) $(RUSTFLAGS) --crate-type=lib --crate-name=openbsd \ + -o $@ src/libopenbsd.rs diff --git a/src/libopenbsd.rs b/src/libopenbsd.rs new file mode 100644 index 0000000..7d98d10 --- /dev/null +++ b/src/libopenbsd.rs @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 Emma Tebibyte + * SPDX-License-Identifier: AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ + +use std::{ + ffi::{ CString, c_int }, + io::Error, + ptr::null, +}; + +mod openbsd { + use std::ffi::{ c_char, c_int }; + extern "C" { + pub fn pledge(arg1: *const c_char, arg2: *const c_char) -> c_int; + + pub fn unveil(arg1: *const c_char, arg2: *const c_char) -> c_int; + + pub fn __errno() -> *mut c_int; + } +} + +pub struct Promises(*const i8); + +impl Promises { + pub fn new(promises: &str) -> Self { + let p = CString::new(promises).unwrap(); + + Promises(p.into_raw() as *const i8) + } +} + +pub fn pledge( + promises: Option, execpromises: Option +) -> Result<(), Error> { + /* From pledge(2): + * + * Passing NULL to promises or execpromises specifies to not change + * the current value. */ + let arg1 = promises.unwrap_or(Promises(null())).0; + let arg2 = execpromises.unwrap_or(Promises(null())).0; + + unsafe { + match openbsd::pledge(arg1, arg2) { + -1 => Err(Error::from_raw_os_error(*openbsd::__errno())), + 0 => Ok(()), + _ => panic!(), /* unreachable */ + } + } +} + +pub struct UnveilPerms(CString); + +impl UnveilPerms { + pub fn new(permissions: Vec) -> Self { + if permissions.is_empty() { + return UnveilPerms(CString::new("").unwrap()); + } + + UnveilPerms( + CString::new(permissions.iter().collect::()).unwrap() + ) + } +} + +pub fn unveil(path: Option<&str>, permissions: Option) -> c_int { + let path_c = path.map(CString::new).map(Result::unwrap); + let arg1 = path_c.map(|p| p.into_raw() as *const i8).unwrap_or(null()); + + let arg2 = permissions + .map(|p| p.0.into_raw() as *const i8) + .unwrap_or(null()); + + unsafe { openbsd::unveil(arg1, arg2) } +}