Merge 1.3.0

This commit is contained in:
Andrew A. Vasilyev 2024-02-29 18:26:40 +03:00
commit e8b153031a
24 changed files with 162 additions and 177 deletions

View File

@ -1,7 +1,7 @@
[package] [package]
name = "pve-lxc-syscalld" name = "pve-lxc-syscalld"
edition = "2021" edition = "2021"
version = "1.2.2" version = "1.3.0"
authors = [ authors = [
"Wolfgang Bumiller <w.bumiller@proxmox.com>", "Wolfgang Bumiller <w.bumiller@proxmox.com>",
] ]
@ -9,13 +9,15 @@ license = "AGPL-3"
description = "Proxmox LXC seccomp-proxy syscall handler daemon" description = "Proxmox LXC seccomp-proxy syscall handler daemon"
homepage = "https://www.proxmox.com" homepage = "https://www.proxmox.com"
exclude = [ "build", "debian" ] rust-version = "1.64"
exclude = [ "debian" ]
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
bitflags = "1.2" bitflags = "1.2"
lazy_static = "1.4" lazy_static = "1.4"
libc = "0.2" libc = "0.2"
nix = "0.24" nix = "0.26"
num_cpus = "1" num_cpus = "1"
tokio = { version = "1.0", features = [ "rt-multi-thread", "io-util", "net" ] } tokio = { version = "1.0", features = [ "rt-multi-thread", "io-util", "net" ] }

View File

@ -20,7 +20,9 @@ COMPILED_BINS := \
$(addprefix $(COMPILEDIR)/,$(SERVICE_BIN)) $(addprefix $(COMPILEDIR)/,$(SERVICE_BIN))
DEB=$(PACKAGE)_$(DEB_VERSION)_$(DEB_HOST_ARCH).deb DEB=$(PACKAGE)_$(DEB_VERSION)_$(DEB_HOST_ARCH).deb
DSC=rust-$(PACKAGE)_$(DEB_VERSION).dsc DSC=$(PACKAGE)_$(DEB_VERSION).dsc
BUILDDIR ?= $(PACKAGE)-$(DEB_VERSION_UPSTREAM)
all: cargo-build $(SUBDIRS) all: cargo-build $(SUBDIRS)
@ -39,12 +41,6 @@ test:
.PHONY: check .PHONY: check
check: test check: test
.PHONY: san
san:
cargo +nightly fmt -- --check
cargo clippy
cargo test
$(COMPILED_BINS): cargo-build $(COMPILED_BINS): cargo-build
install: $(COMPILED_BINS) install: $(COMPILED_BINS)
@ -52,43 +48,38 @@ install: $(COMPILED_BINS)
$(foreach i,$(SERVICE_BIN), \ $(foreach i,$(SERVICE_BIN), \
install -m755 $(COMPILEDIR)/$(i) $(DESTDIR)$(LIBEXECDIR)/pve-lxc-syscalld/ ;) install -m755 $(COMPILEDIR)/$(i) $(DESTDIR)$(LIBEXECDIR)/pve-lxc-syscalld/ ;)
.PHONY: build $(BUILDDIR): src debian etc Cargo.toml
build: rm -rf $(BUILDDIR) $(BUILDDIR).tmp
rm -rf build mkdir $(BUILDDIR).tmp
debcargo package \ #mkdir $(BUILDDIR).tmp/.cargo
--config debian/debcargo.toml \ cp -a -t $(BUILDDIR).tmp $^ Makefile defines.mk
--changelog-ready \ #cp -a -t $(BUILDDIR).tmp/.cargo .cargo/config
--no-overlay-write-back \ echo "git clone git://git.proxmox.com/git/pve-lxc-syscalld.git\\ngit checkout $(shell git rev-parse HEAD)" > $(BUILDDIR).tmp/debian/SOURCE
--directory build \ mv $(BUILDDIR).tmp $(BUILDDIR)
pve-lxc-syscalld \
$(shell dpkg-parsechangelog -l debian/changelog -SVersion | sed -e 's/-.*//')
sed -e '1,/^$$/ ! d' build/debian/control > build/debian/control.src
cat build/debian/control.src build/debian/control.in > build/debian/control
rm build/debian/control.in build/debian/control.src
rm build/Cargo.lock
find build/debian -name "*.hint" -delete
echo system >build/rust-toolchain
$(foreach i,$(SUBDIRS), \
$(MAKE) -C build/$(i) clean ;)
.PHONY: deb .PHONY: deb
deb: $(DEB) deb: $(DEB)
$(DEB): build $(DEB): $(BUILDDIR)
cd build; dpkg-buildpackage -b -us -uc --no-pre-clean --build-profiles=nodoc cd $(BUILDDIR); dpkg-buildpackage -b -us -uc
lintian $(DEB) lintian $(DEB)
upload: deb
dcmd --deb rust-pve-lxc-syscalld_*.changes \
| grep -v '.changes$$' \
| tar -cf- -T- \
| ssh -X repoman@repo.proxmox.com upload --product pve --dist bullseye
.PHONY: dsc .PHONY: dsc
dsc: $(DSC) dsc: $(DSC)
$(DSC): build $(DSC): $(BUILDDIR)
cd build; dpkg-buildpackage -S -us -uc -d -nc cd $(BUILDDIR); dpkg-buildpackage -S -us -uc -d
lintian $(DSC) lintian $(DSC)
sbuild: $(DSC)
sbuild $(DSC)
.PHONY: upload
upload: UPLOAD_DIST ?= $(DEB_DISTRIBUTION)
upload: $(DEB)
dcmd --deb pve-lxc-syscalld_*.changes \
| grep -v '.changes$$' \
| tar -cf- -T- \
| ssh -X repoman@repo.proxmox.com upload --product pve --dist $(UPLOAD_DIST)
.PHONY: dinstall .PHONY: dinstall
dinstall: dinstall:
$(MAKE) deb $(MAKE) deb
@ -97,5 +88,6 @@ dinstall:
clean: clean:
$(foreach i,$(SUBDIRS), \ $(foreach i,$(SUBDIRS), \
$(MAKE) -C $(i) clean ;) $(MAKE) -C $(i) clean ;)
cargo clean rm -rf ./target
rm -rf *.deb *.dsc *.tar.gz *.buildinfo *.changes build rm -rf ./$(BUILDDIR)
rm -f -- *.deb *.dsc *.tar.?z *.buildinfo *.build *.changes

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
pve-lxc-syscalld (1.3.0) bookworm; urgency=medium
* rebuild for Debian 12 bookworm based release series
-- Proxmox Support Team <support@proxmox.com> Wed, 24 May 2023 13:33:14 +0200
rust-pve-lxc-syscalld (1.2.2-1) pve; urgency=medium rust-pve-lxc-syscalld (1.2.2-1) pve; urgency=medium
* remove old poll/event handling for SEQPACKET socket * remove old poll/event handling for SEQPACKET socket

1
debian/compat vendored
View File

@ -1 +0,0 @@
12

33
debian/control vendored Normal file
View File

@ -0,0 +1,33 @@
Source: pve-lxc-syscalld
Section: admin
Priority: optional
Build-Depends: debhelper-compat (= 13),
bash-completion,
libsystemd-dev,
dh-cargo (>= 25),
cargo:native,
rustc:native,
libstd-rust-dev,
librust-anyhow-1+default-dev,
librust-bitflags-1+default-dev (>= 1.2-~~),
librust-lazy-static-1+default-dev (>= 1.4-~~),
librust-libc-0.2+default-dev,
librust-nix-0.26+default-dev,
librust-num-cpus-1+default-dev,
librust-tokio-1+default-dev,
librust-tokio-1+io-util-dev,
librust-tokio-1+net-dev,
librust-tokio-1+rt-multi-thread-dev,
Maintainer: Proxmox Support Team <support@proxmox.com>
Standards-Version: 4.6.1
Vcs-Git: git://git.proxmox.com/git/pve-lxc-syscalld.git
Vcs-Browser: https://git.proxmox.com/?p=pve-lxc-syscalld.git;a=summary
Homepage: https://www.proxmox.com
Rules-Requires-Root: no
Package: pve-lxc-syscalld
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends},
Description: PVE LXC syscall daemon
A daemon which handles a selected subset of syscalls for unprivileged
containers.

6
debian/control.in vendored
View File

@ -1,6 +0,0 @@
Package: pve-lxc-syscalld
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends},
Description: PVE LXC syscall daemon
A daemon which handles a selected subset of syscalls for unprivileged
containers.

32
debian/copyright vendored
View File

@ -1,16 +1,18 @@
Copyright (C) 2019,2020 Proxmox Server Solutions GmbH Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
This software is written by Proxmox Server Solutions GmbH <support@proxmox.com> Files:
*
This program is free software: you can redistribute it and/or modify Copyright: 2019 - 2023 Proxmox Server Solutions GmbH <support@proxmox.com>
it under the terms of the GNU Affero General Public License as published by License: AGPL-3.0-or-later
the Free Software Foundation, either version 3 of the License, or This program is free software: you can redistribute it and/or modify it under
(at your option) any later version. 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
This program is distributed in the hope that it will be useful, later version.
but WITHOUT ANY WARRANTY; without even the implied warranty of .
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the This program is distributed in the hope that it will be useful, but WITHOUT
GNU Affero General Public License for more details. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
You should have received a copy of the GNU Affero General Public License details.
along with this program. If not, see <http://www.gnu.org/licenses/>. .
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/>.

11
debian/debcargo.toml vendored
View File

@ -1,11 +0,0 @@
overlay = "."
crate_src_path = ".."
maintainer = "Proxmox Support Team <support@proxmox.com>"
[source]
section = "admin"
build_depends = [ "debhelper (>= 12~)", "bash-completion" ]
build_depends_excludes = [ "debhelper (>=11)" ]
# TODO:
vcs_git = ""
vcs_browser = ""

2
debian/rules vendored
View File

@ -21,6 +21,8 @@ export DEB_CARGO_PACKAGE=pve-lxc-syscalld
dh $@ dh $@
override_dh_auto_configure: override_dh_auto_configure:
@perl -ne 'if (/^version\s*=\s*"(\d+(?:\.\d+)+)"/) { my $$v_cargo = $$1; my $$v_deb = "$(DEB_VERSION_UPSTREAM)"; \
die "ERROR: d/changelog <-> Cargo.toml version mismatch: $$v_cargo != $$v_deb\n" if $$v_cargo ne $$v_deb; exit(0); }' Cargo.toml
$(CARGO) prepare-debian $(CURDIR)/debian/cargo_registry --link-from-system $(CARGO) prepare-debian $(CURDIR)/debian/cargo_registry --link-from-system
dh_auto_configure dh_auto_configure

View File

@ -1 +1 @@
3.0 (quilt) 3.0 (native)

View File

@ -1 +0,0 @@
edition = "2018"

View File

@ -23,9 +23,9 @@ impl Client {
F: std::future::Future<Output = Result<(), Error>>, F: std::future::Future<Output = Result<(), Error>>,
{ {
if let Err(err) = fut.await { if let Err(err) = fut.await {
eprintln!("client error, dropping connection: {}", err); eprintln!("client error, dropping connection: {err}");
if let Err(err) = self.socket.shutdown(nix::sys::socket::Shutdown::Both) { if let Err(err) = self.socket.shutdown(nix::sys::socket::Shutdown::Both) {
eprintln!(" (error shutting down client socket: {})", err); eprintln!(" (error shutting down client socket: {err})");
} }
} }
} }

View File

@ -57,9 +57,9 @@ impl Fork {
let pid = c_try!(unsafe { libc::fork() }); let pid = c_try!(unsafe { libc::fork() });
if pid == 0 { if pid == 0 {
drop(pipe_r); drop(pipe_r);
let mut pipe_w = pipe_w.into_fd(); let pipe_w = pipe_w.into_fd();
let _ = std::panic::catch_unwind(move || { let _ = std::panic::catch_unwind(move || {
pipe_w.set_nonblocking(false).unwrap(); crate::tools::set_fd_nonblocking(&pipe_w, false).unwrap();
let mut pipe_w = unsafe { std::fs::File::from_raw_fd(pipe_w.into_raw_fd()) }; let mut pipe_w = unsafe { std::fs::File::from_raw_fd(pipe_w.into_raw_fd()) };
let out = match func() { let out = match func() {
Ok(SyscallStatus::Ok(val)) => Data { Ok(SyscallStatus::Ok(val)) => Data {

View File

@ -47,7 +47,7 @@ impl<'a> Iterator for RawCmsgIterator<'a> {
let hdr: cmsghdr = unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const cmsghdr) }; let hdr: cmsghdr = unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const cmsghdr) };
let data_off = mem::size_of::<cmsghdr>(); let data_off = mem::size_of::<cmsghdr>();
let data_end = hdr.cmsg_len; let data_end = hdr.cmsg_len;
let next_hdr = align(hdr.cmsg_len as usize); let next_hdr = align(hdr.cmsg_len);
let data = &buf[data_off..data_end]; let data = &buf[data_off..data_end];
let item = ControlMessageRef { let item = ControlMessageRef {
cmsg_level: hdr.cmsg_level, cmsg_level: hdr.cmsg_level,

View File

@ -1,16 +1,14 @@
use std::io; use std::io;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, OwnedFd, RawFd};
use tokio::io::unix::AsyncFd; use tokio::io::unix::AsyncFd;
use crate::tools::Fd;
pub mod cmsg; pub mod cmsg;
pub mod pipe; pub mod pipe;
pub mod rw_traits; pub mod rw_traits;
pub mod seq_packet; pub mod seq_packet;
pub async fn wrap_read<R, F>(async_fd: &AsyncFd<Fd>, mut call: F) -> io::Result<R> pub async fn wrap_read<R, F>(async_fd: &AsyncFd<OwnedFd>, mut call: F) -> io::Result<R>
where where
F: FnMut(RawFd) -> io::Result<R>, F: FnMut(RawFd) -> io::Result<R>,
{ {
@ -28,7 +26,7 @@ where
} }
} }
pub async fn wrap_write<R, F>(async_fd: &AsyncFd<Fd>, mut call: F) -> io::Result<R> pub async fn wrap_write<R, F>(async_fd: &AsyncFd<OwnedFd>, mut call: F) -> io::Result<R>
where where
F: FnMut(RawFd) -> io::Result<R>, F: FnMut(RawFd) -> io::Result<R>,
{ {

View File

@ -1,15 +1,14 @@
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use std::io; use std::io;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{ready, Context, Poll};
use tokio::io::unix::AsyncFd; use tokio::io::unix::AsyncFd;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use crate::io::rw_traits; use crate::io::rw_traits;
use crate::tools::Fd;
pub use rw_traits::{Read, Write}; pub use rw_traits::{Read, Write};
@ -20,15 +19,15 @@ pub use rw_traits::{Read, Write};
/// from the reactor, which will just break. /// from the reactor, which will just break.
/// ///
/// So we start out with this type which can be "upgraded" or "downgraded" into a `Pipe<T>` or /// So we start out with this type which can be "upgraded" or "downgraded" into a `Pipe<T>` or
/// `Fd`. /// `OwnedFd`.
pub struct PipeFd<RW>(Fd, PhantomData<RW>); pub struct PipeFd<RW>(OwnedFd, PhantomData<RW>);
impl<RW> PipeFd<RW> { impl<RW> PipeFd<RW> {
pub fn new(fd: Fd) -> Self { pub fn new(fd: OwnedFd) -> Self {
Self(fd, PhantomData) Self(fd, PhantomData)
} }
pub fn into_fd(self) -> Fd { pub fn into_fd(self) -> OwnedFd {
self.0 self.0
} }
} }
@ -38,7 +37,7 @@ pub fn pipe_fds() -> io::Result<(PipeFd<rw_traits::Read>, PipeFd<rw_traits::Writ
c_try!(unsafe { libc::pipe2(pfd.as_mut_ptr(), libc::O_CLOEXEC) }); c_try!(unsafe { libc::pipe2(pfd.as_mut_ptr(), libc::O_CLOEXEC) });
let (fd_in, fd_out) = unsafe { (Fd::from_raw_fd(pfd[0]), Fd::from_raw_fd(pfd[1])) }; let (fd_in, fd_out) = unsafe { (OwnedFd::from_raw_fd(pfd[0]), OwnedFd::from_raw_fd(pfd[1])) };
Ok((PipeFd::new(fd_in), PipeFd::new(fd_out))) Ok((PipeFd::new(fd_in), PipeFd::new(fd_out)))
} }
@ -46,7 +45,7 @@ pub fn pipe_fds() -> io::Result<(PipeFd<rw_traits::Read>, PipeFd<rw_traits::Writ
/// Tokio supported pipe file descriptor. `tokio::fs::File` requires tokio's complete file system /// Tokio supported pipe file descriptor. `tokio::fs::File` requires tokio's complete file system
/// feature gate, so we just use this `AsyncFd` wrapper. /// feature gate, so we just use this `AsyncFd` wrapper.
pub struct Pipe<RW> { pub struct Pipe<RW> {
fd: AsyncFd<Fd>, fd: AsyncFd<OwnedFd>,
_phantom: PhantomData<RW>, _phantom: PhantomData<RW>,
} }

View File

@ -1,5 +1,5 @@
use std::io::{self, IoSlice, IoSliceMut}; use std::io::{self, IoSlice, IoSliceMut};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
use std::ptr; use std::ptr;
use anyhow::Error; use anyhow::Error;
@ -7,20 +7,19 @@ use nix::sys::socket::{self, AddressFamily, SockFlag, SockType, SockaddrLike};
use tokio::io::unix::AsyncFd; use tokio::io::unix::AsyncFd;
use crate::tools::AssertSendSync; use crate::tools::AssertSendSync;
use crate::tools::Fd;
fn seq_packet_socket(flags: SockFlag) -> nix::Result<Fd> { fn seq_packet_socket(flags: SockFlag) -> nix::Result<OwnedFd> {
let fd = socket::socket( let fd = socket::socket(
AddressFamily::Unix, AddressFamily::Unix,
SockType::SeqPacket, SockType::SeqPacket,
flags | SockFlag::SOCK_CLOEXEC, flags | SockFlag::SOCK_CLOEXEC,
None, None,
)?; )?;
Ok(unsafe { Fd::from_raw_fd(fd) }) Ok(unsafe { OwnedFd::from_raw_fd(fd) })
} }
pub struct SeqPacketListener { pub struct SeqPacketListener {
fd: AsyncFd<Fd>, fd: AsyncFd<OwnedFd>,
} }
impl AsRawFd for SeqPacketListener { impl AsRawFd for SeqPacketListener {
@ -54,13 +53,13 @@ impl SeqPacketListener {
}) })
.await?; .await?;
let fd = unsafe { Fd::from_raw_fd(fd as RawFd) }; let fd = unsafe { OwnedFd::from_raw_fd(fd as RawFd) };
SeqPacketSocket::new(fd) SeqPacketSocket::new(fd)
} }
} }
pub struct SeqPacketSocket { pub struct SeqPacketSocket {
fd: AsyncFd<Fd>, fd: AsyncFd<OwnedFd>,
} }
impl AsRawFd for SeqPacketSocket { impl AsRawFd for SeqPacketSocket {
@ -71,7 +70,7 @@ impl AsRawFd for SeqPacketSocket {
} }
impl SeqPacketSocket { impl SeqPacketSocket {
pub fn new(fd: Fd) -> io::Result<Self> { pub fn new(fd: OwnedFd) -> io::Result<Self> {
Ok(Self { Ok(Self {
fd: AsyncFd::new(fd)?, fd: AsyncFd::new(fd)?,
}) })
@ -125,7 +124,7 @@ impl SeqPacketSocket {
}); });
let data_size = self.recvmsg(&mut msg).await?; let data_size = self.recvmsg(&mut msg).await?;
Ok((data_size, msg.0.msg_controllen as usize)) Ok((data_size, msg.0.msg_controllen))
} }
#[inline] #[inline]

View File

@ -6,7 +6,7 @@ use std::io::{self, IoSlice, IoSliceMut};
use std::mem; use std::mem;
use std::os::raw::{c_int, c_uint}; use std::os::raw::{c_int, c_uint};
use std::os::unix::fs::FileExt; use std::os::unix::fs::FileExt;
use std::os::unix::io::{FromRawFd, RawFd}; use std::os::unix::io::{FromRawFd, OwnedFd, RawFd};
use anyhow::{bail, format_err, Error}; use anyhow::{bail, format_err, Error};
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -17,7 +17,7 @@ use crate::io::cmsg;
use crate::io::seq_packet::SeqPacketSocket; use crate::io::seq_packet::SeqPacketSocket;
use crate::process::PidFd; use crate::process::PidFd;
use crate::seccomp::{SeccompNotif, SeccompNotifResp, SeccompNotifSizes}; use crate::seccomp::{SeccompNotif, SeccompNotifResp, SeccompNotifSizes};
use crate::tools::{Fd, FromFd}; use crate::tools::FromFd;
/// Seccomp notification proxy message sent by the lxc monitor. /// Seccomp notification proxy message sent by the lxc monitor.
/// ///
@ -82,7 +82,7 @@ unsafe fn io_vec<T>(value: &T) -> IoSlice {
lazy_static! { lazy_static! {
static ref SECCOMP_SIZES: SeccompNotifSizes = SeccompNotifSizes::get_checked() static ref SECCOMP_SIZES: SeccompNotifSizes = SeccompNotifSizes::get_checked()
.map_err(|e| panic!("{}\nrefusing to run", e)) .map_err(|e| panic!("{e}\nrefusing to run"))
.unwrap(); .unwrap();
} }
@ -153,13 +153,13 @@ impl ProxyMessageBuffer {
bail!("expected SCM_RIGHTS control message"); bail!("expected SCM_RIGHTS control message");
} }
let fds: Vec<Fd> = cmsg let fds: Vec<OwnedFd> = cmsg
.data .data
.chunks_exact(mem::size_of::<RawFd>()) .chunks_exact(mem::size_of::<RawFd>())
.map(|chunk| unsafe { .map(|chunk| unsafe {
// clippy bug // clippy bug
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
Fd::from_raw_fd(std::ptr::read_unaligned(chunk.as_ptr() as _)) OwnedFd::from_raw_fd(std::ptr::read_unaligned(chunk.as_ptr() as _))
}) })
.collect(); .collect();
@ -394,7 +394,7 @@ impl ProxyMessageBuffer {
/// Checked way to get a file descriptor argument. /// Checked way to get a file descriptor argument.
#[inline] #[inline]
pub fn arg_fd(&self, arg: u32, flags: c_int) -> Result<Fd, Error> { pub fn arg_fd(&self, arg: u32, flags: c_int) -> Result<OwnedFd, Error> {
let fd = self.arg(arg)? as RawFd; let fd = self.arg(arg)? as RawFd;
// we pass negative ones 'as-is', others get opened via the pidfd // we pass negative ones 'as-is', others get opened via the pidfd
Ok(if fd == libc::AT_FDCWD { Ok(if fd == libc::AT_FDCWD {
@ -402,7 +402,7 @@ impl ProxyMessageBuffer {
// might want to reuse this one? // might want to reuse this one?
self.pid_fd().fd_cwd()? self.pid_fd().fd_cwd()?
} else if fd < 0 { } else if fd < 0 {
Fd(fd) unsafe { OwnedFd::from_raw_fd(fd) }
} else { } else {
self.pid_fd().fd_num(fd, flags)? self.pid_fd().fd_num(fd, flags)?
}) })

View File

@ -10,12 +10,12 @@ macro_rules! c_str {
macro_rules! file_descriptor_type { macro_rules! file_descriptor_type {
($type:ident) => { ($type:ident) => {
#[repr(transparent)] #[repr(transparent)]
pub struct $type(RawFd); pub struct $type(::std::os::unix::io::RawFd);
file_descriptor_impl!($type); file_descriptor_impl!($type);
impl FromRawFd for $type { impl ::std::os::unix::io::FromRawFd for $type {
unsafe fn from_raw_fd(fd: RawFd) -> Self { unsafe fn from_raw_fd(fd: ::std::os::unix::io::RawFd) -> Self {
Self(fd) Self(fd)
} }
} }
@ -34,14 +34,20 @@ macro_rules! file_descriptor_impl {
} }
} }
impl AsRawFd for $type { impl ::std::os::unix::io::AsFd for $type {
fn as_raw_fd(&self) -> RawFd { fn as_fd(&self) -> ::std::os::unix::io::BorrowedFd<'_> {
unsafe { ::std::os::unix::io::BorrowedFd::borrow_raw(self.0) }
}
}
impl ::std::os::unix::io::AsRawFd for $type {
fn as_raw_fd(&self) -> ::std::os::unix::io::RawFd {
self.0 self.0
} }
} }
impl IntoRawFd for $type { impl ::std::os::unix::io::IntoRawFd for $type {
fn into_raw_fd(mut self) -> RawFd { fn into_raw_fd(mut self) -> ::std::os::unix::io::RawFd {
let fd = self.0; let fd = self.0;
self.0 = -libc::EBADF; self.0 = -libc::EBADF;
fd fd
@ -78,13 +84,3 @@ macro_rules! io_bail {
return Err(::std::io::Error::new(::std::io::ErrorKind::Other, format!($($msg)*))); return Err(::std::io::Error::new(::std::io::ErrorKind::Other, format!($($msg)*)));
}; };
} }
macro_rules! ready {
($expr:expr) => {{
use std::task::Poll;
match $expr {
Poll::Ready(v) => v,
Poll::Pending => return Poll::Pending,
}
}};
}

View File

@ -106,12 +106,12 @@ fn main() {
let rt = tokio::runtime::Builder::new_multi_thread() let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all() .enable_all()
.worker_threads(cpus.max(2).min(4)) .worker_threads(cpus.clamp(2, 4))
.build() .build()
.expect("failed to spawn tokio runtime"); .expect("failed to spawn tokio runtime");
if let Err(err) = rt.block_on(do_main(use_sd_notify, path)) { if let Err(err) = rt.block_on(do_main(use_sd_notify, path)) {
eprintln!("error: {}", err); eprintln!("error: {err}");
std::process::exit(1); std::process::exit(1);
} }
} }

View File

@ -4,7 +4,7 @@ use std::ffi::CStr;
use std::io; use std::io;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::raw::c_int; use std::os::raw::c_int;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::os::unix::io::RawFd;
pub mod ns_type { pub mod ns_type {
pub trait NsType { pub trait NsType {

View File

@ -4,7 +4,7 @@ use std::ffi::{CStr, CString, OsString};
use std::io::{self, BufRead, BufReader}; use std::io::{self, BufRead, BufReader};
use std::os::raw::c_int; use std::os::raw::c_int;
use std::os::unix::ffi::OsStringExt; use std::os::unix::ffi::OsStringExt;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use anyhow::{bail, Error}; use anyhow::{bail, Error};
use libc::pid_t; use libc::pid_t;
@ -12,7 +12,6 @@ use libc::pid_t;
use crate::capability::Capabilities; use crate::capability::Capabilities;
use crate::error::io_err_other; use crate::error::io_err_other;
use crate::nsfd::{ns_type, NsFd}; use crate::nsfd::{ns_type, NsFd};
use crate::tools::Fd;
use super::{CGroups, IdMap, IdMapEntry, ProcStatus, Uids, UserCaps}; use super::{CGroups, IdMap, IdMapEntry, ProcStatus, Uids, UserCaps};
@ -25,7 +24,7 @@ impl PidFd {
} }
pub fn open(pid: pid_t) -> io::Result<Self> { pub fn open(pid: pid_t) -> io::Result<Self> {
let path = CString::new(format!("/proc/{}", pid)).unwrap(); let path = CString::new(format!("/proc/{pid}")).unwrap();
let fd = c_try!(unsafe { libc::open(path.as_ptr(), libc::O_DIRECTORY | libc::O_CLOEXEC) }); let fd = c_try!(unsafe { libc::open(path.as_ptr(), libc::O_DIRECTORY | libc::O_CLOEXEC) });
@ -38,7 +37,7 @@ impl PidFd {
/// ///
/// The file descriptor must already be a valid pidfd, this is not checked. This function only /// The file descriptor must already be a valid pidfd, this is not checked. This function only
/// fails if reading the pid from the pidfd's proc entry fails. /// fails if reading the pid from the pidfd's proc entry fails.
pub unsafe fn try_from_fd(fd: Fd) -> io::Result<Self> { pub unsafe fn try_from_fd(fd: OwnedFd) -> io::Result<Self> {
#[allow(clippy::unnecessary_cast)] // pid_t is a type alias #[allow(clippy::unnecessary_cast)] // pid_t is a type alias
let mut this = Self(fd.into_raw_fd(), -1 as pid_t); let mut this = Self(fd.into_raw_fd(), -1 as pid_t);
let pid = this.read_pid()?; let pid = this.read_pid()?;
@ -58,23 +57,23 @@ impl PidFd {
NsFd::openat(self.0, c_str!("ns/user")) NsFd::openat(self.0, c_str!("ns/user"))
} }
fn fd(&self, path: &CStr, flags: c_int, mode: c_int) -> io::Result<Fd> { fn fd(&self, path: &CStr, flags: c_int, mode: c_int) -> io::Result<OwnedFd> {
Ok(Fd(c_try!(unsafe { Ok(unsafe {
libc::openat( OwnedFd::from_raw_fd(c_try!(libc::openat(
self.as_raw_fd(), self.as_raw_fd(),
path.as_ptr() as *const _, path.as_ptr() as *const _,
flags | libc::O_CLOEXEC, flags | libc::O_CLOEXEC,
mode, mode,
) )))
}))) })
} }
pub fn fd_cwd(&self) -> io::Result<Fd> { pub fn fd_cwd(&self) -> io::Result<OwnedFd> {
self.fd(c_str!("cwd"), libc::O_DIRECTORY, 0) self.fd(c_str!("cwd"), libc::O_DIRECTORY, 0)
} }
pub fn fd_num(&self, num: RawFd, flags: c_int) -> io::Result<Fd> { pub fn fd_num(&self, num: RawFd, flags: c_int) -> io::Result<OwnedFd> {
let path = format!("fd/{}\0", num); let path = format!("fd/{num}\0");
self.fd( self.fd(
unsafe { CStr::from_bytes_with_nul_unchecked(path.as_bytes()) }, unsafe { CStr::from_bytes_with_nul_unchecked(path.as_bytes()) },
flags, flags,

View File

@ -1,5 +1,5 @@
use std::ffi::CString; use std::ffi::CString;
use std::os::unix::io::AsRawFd; use std::os::unix::io::{AsRawFd, OwnedFd};
use anyhow::Error; use anyhow::Error;
use nix::errno::Errno; use nix::errno::Errno;
@ -10,7 +10,6 @@ use crate::lxcseccomp::ProxyMessageBuffer;
use crate::process::PidFd; use crate::process::PidFd;
use crate::sc_libc_try; use crate::sc_libc_try;
use crate::syscall::SyscallStatus; use crate::syscall::SyscallStatus;
use crate::tools::Fd;
pub async fn mknod(msg: &ProxyMessageBuffer) -> Result<SyscallStatus, Error> { pub async fn mknod(msg: &ProxyMessageBuffer) -> Result<SyscallStatus, Error> {
let mode = msg.arg_mode_t(1)?; let mode = msg.arg_mode_t(1)?;
@ -61,7 +60,7 @@ fn check_mknod_dev(mode: stat::mode_t, dev: stat::dev_t) -> bool {
async fn do_mknodat( async fn do_mknodat(
pidfd: &PidFd, pidfd: &PidFd,
dirfd: Fd, dirfd: OwnedFd,
pathname: CString, pathname: CString,
mode: stat::mode_t, mode: stat::mode_t,
dev: stat::dev_t, dev: stat::dev_t,

View File

@ -3,37 +3,14 @@
//! Note that this should stay small, otherwise we should introduce a dependency on our `proxmox` //! Note that this should stay small, otherwise we should introduce a dependency on our `proxmox`
//! crate as that's where we have all this stuff usually... //! crate as that's where we have all this stuff usually...
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
/// Guard a raw file descriptor with a drop handler. This is mostly useful when access to an owned pub fn set_fd_nonblocking<T: AsRawFd + ?Sized>(fd: &T, on: bool) -> nix::Result<libc::c_int> {
/// `RawFd` is required without the corresponding handler object (such as when only the file
/// descriptor number is required in a closure which may be dropped instead of being executed).
#[repr(transparent)]
pub struct Fd(pub RawFd);
file_descriptor_impl!(Fd);
impl FromRawFd for Fd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self(fd)
}
}
impl Fd {
pub fn set_nonblocking(&mut self, nb: bool) -> nix::Result<libc::c_int> {
use nix::fcntl; use nix::fcntl;
let mut flags = let fd = fd.as_raw_fd();
fcntl::OFlag::from_bits(fcntl::fcntl(self.0, fcntl::FcntlArg::F_GETFL)?).unwrap(); let mut flags = fcntl::OFlag::from_bits(fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL)?).unwrap();
flags.set(fcntl::OFlag::O_NONBLOCK, nb); flags.set(fcntl::OFlag::O_NONBLOCK, on);
fcntl::fcntl(self.0, fcntl::FcntlArg::F_SETFL(flags)) fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFL(flags))
}
}
impl AsRef<RawFd> for Fd {
#[inline]
fn as_ref(&self) -> &RawFd {
&self.0
}
} }
/// Byte vector utilities. /// Byte vector utilities.
@ -62,11 +39,11 @@ pub mod vec {
} }
pub trait FromFd { pub trait FromFd {
fn from_fd(fd: Fd) -> Self; fn from_fd<T: IntoRawFd>(fd: T) -> Self;
} }
impl<T: FromRawFd> FromFd for T { impl<T: FromRawFd> FromFd for T {
fn from_fd(fd: Fd) -> Self { fn from_fd<F: IntoRawFd>(fd: F) -> Self {
unsafe { Self::from_raw_fd(fd.into_raw_fd()) } unsafe { Self::from_raw_fd(fd.into_raw_fd()) }
} }
} }