Support SO_PEERCRED & SO_PEERGROUPS
This commit is contained in:
parent
d7e88f93bd
commit
e4c5c36be9
|
|
@ -52,6 +52,7 @@ typeflags::typeflags! {
|
|||
pub type Full = TRightSet<TRights![Dup, Read, Write, Exec, Signal]>;
|
||||
pub type ReadOp = TRights![Read];
|
||||
pub type WriteOp = TRights![Write];
|
||||
pub type ReadDupOp = TRights![Read, Dup];
|
||||
pub type FullOp = TRights![Read, Write, Dup];
|
||||
|
||||
/// Wrapper for TRights, used to bypass an error message from the Rust compiler,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::util::LingerOption;
|
||||
use crate::{impl_socket_options, prelude::*};
|
||||
use crate::{impl_socket_options, net::socket::unix::CUserCred, prelude::*, process::Gid};
|
||||
|
||||
mod macros;
|
||||
|
||||
|
|
@ -21,7 +21,9 @@ impl_socket_options!(
|
|||
pub struct Priority(i32);
|
||||
pub struct Linger(LingerOption);
|
||||
pub struct KeepAlive(bool);
|
||||
pub struct PeerCred(CUserCred);
|
||||
pub struct AcceptConn(bool);
|
||||
pub struct SendBufForce(u32);
|
||||
pub struct RecvBufForce(u32);
|
||||
pub struct PeerGroups(Arc<[Gid]>);
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use aster_rights::{Dup, Read, ReadDupOp, ReadOp, TRights};
|
||||
use aster_rights_proc::require;
|
||||
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::{posix_thread::AsPosixThread, Credentials, Gid, Pid, Uid},
|
||||
};
|
||||
|
||||
pub(super) struct SocketCred<R = ReadOp> {
|
||||
pid: Pid,
|
||||
cred: Credentials<R>,
|
||||
}
|
||||
|
||||
impl SocketCred<ReadOp> {
|
||||
pub(super) fn new_current() -> Self {
|
||||
let pid = current!().pid();
|
||||
let cred = current_thread!().as_posix_thread().unwrap().credentials();
|
||||
|
||||
Self { pid, cred }
|
||||
}
|
||||
}
|
||||
|
||||
impl SocketCred<ReadDupOp> {
|
||||
pub(super) fn new_current() -> Self {
|
||||
let pid = current!().pid();
|
||||
let cred = current_thread!()
|
||||
.as_posix_thread()
|
||||
.unwrap()
|
||||
.credentials_dup();
|
||||
|
||||
Self { pid, cred }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TRights> SocketCred<R> {
|
||||
#[require(R > Read)]
|
||||
pub(super) fn to_c_user_cred(&self) -> CUserCred {
|
||||
CUserCred {
|
||||
pid: self.pid,
|
||||
uid: self.cred.euid(),
|
||||
gid: self.cred.egid(),
|
||||
}
|
||||
}
|
||||
|
||||
#[require(R > Read)]
|
||||
pub(super) fn groups(&self) -> Arc<[Gid]> {
|
||||
self.cred.groups().iter().cloned().collect()
|
||||
}
|
||||
|
||||
#[require(R > R1)]
|
||||
pub(super) fn restrict<R1: TRights>(self) -> SocketCred<R1> {
|
||||
let Self { pid, cred } = self;
|
||||
SocketCred {
|
||||
pid,
|
||||
cred: cred.restrict(),
|
||||
}
|
||||
}
|
||||
|
||||
#[require(R > Dup)]
|
||||
pub(super) fn dup(&self) -> Self {
|
||||
Self {
|
||||
pid: self.pid,
|
||||
cred: self.cred.dup(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reference: <https://elixir.bootlin.com/linux/v6.15/source/include/linux/socket.h#L183>.
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct CUserCred {
|
||||
pid: Pid,
|
||||
uid: Uid,
|
||||
gid: Gid,
|
||||
}
|
||||
|
||||
impl CUserCred {
|
||||
pub(in crate::net) const fn new_unknown() -> Self {
|
||||
Self {
|
||||
pid: 0,
|
||||
uid: Uid::INVALID,
|
||||
gid: Gid::INVALID,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
mod addr;
|
||||
mod cred;
|
||||
mod ns;
|
||||
mod stream;
|
||||
|
||||
pub use addr::UnixSocketAddr;
|
||||
pub use cred::CUserCred;
|
||||
pub use stream::UnixStreamSocket;
|
||||
pub(super) use stream::UNIX_STREAM_DEFAULT_BUF_SIZE;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
events::IoEvents,
|
||||
fs::utils::{Endpoint, EndpointState},
|
||||
net::socket::{
|
||||
unix::{addr::UnixSocketAddrBound, UnixSocketAddr},
|
||||
unix::{addr::UnixSocketAddrBound, cred::SocketCred, UnixSocketAddr},
|
||||
util::SockShutdownCmd,
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -19,6 +19,7 @@ pub(super) struct Connected {
|
|||
inner: Endpoint<Inner>,
|
||||
reader: Mutex<RbConsumer<u8>>,
|
||||
writer: Mutex<RbProducer<u8>>,
|
||||
peer_cred: SocketCred,
|
||||
}
|
||||
|
||||
impl Connected {
|
||||
|
|
@ -27,6 +28,8 @@ impl Connected {
|
|||
peer_addr: Option<UnixSocketAddrBound>,
|
||||
state: EndpointState,
|
||||
peer_state: EndpointState,
|
||||
cred: SocketCred,
|
||||
peer_cred: SocketCred,
|
||||
) -> (Connected, Connected) {
|
||||
let (this_writer, peer_reader) = RingBuffer::new(UNIX_STREAM_DEFAULT_BUF_SIZE).split();
|
||||
let (peer_writer, this_reader) = RingBuffer::new(UNIX_STREAM_DEFAULT_BUF_SIZE).split();
|
||||
|
|
@ -46,11 +49,13 @@ impl Connected {
|
|||
inner: this_inner,
|
||||
reader: Mutex::new(this_reader),
|
||||
writer: Mutex::new(this_writer),
|
||||
peer_cred,
|
||||
};
|
||||
let peer = Connected {
|
||||
inner: peer_inner,
|
||||
reader: Mutex::new(peer_reader),
|
||||
writer: Mutex::new(peer_writer),
|
||||
peer_cred: cred,
|
||||
};
|
||||
|
||||
(this, peer)
|
||||
|
|
@ -144,6 +149,10 @@ impl Connected {
|
|||
pub(super) fn cloned_pollee(&self) -> Pollee {
|
||||
self.inner.this_end().state.cloned_pollee()
|
||||
}
|
||||
|
||||
pub(super) fn peer_cred(&self) -> &SocketCred {
|
||||
&self.peer_cred
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Connected {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use aster_rights::ReadOp;
|
||||
|
||||
use super::{
|
||||
connected::Connected,
|
||||
listener::Listener,
|
||||
|
|
@ -11,7 +13,10 @@ use crate::{
|
|||
events::IoEvents,
|
||||
fs::utils::EndpointState,
|
||||
net::socket::{
|
||||
unix::addr::{UnixSocketAddr, UnixSocketAddrBound},
|
||||
unix::{
|
||||
addr::{UnixSocketAddr, UnixSocketAddrBound},
|
||||
cred::SocketCred,
|
||||
},
|
||||
util::SockShutdownCmd,
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -48,6 +53,7 @@ impl Init {
|
|||
self,
|
||||
peer_addr: UnixSocketAddrBound,
|
||||
pollee: Pollee,
|
||||
peer_cred: SocketCred,
|
||||
) -> (Connected, Connected) {
|
||||
let Init {
|
||||
addr,
|
||||
|
|
@ -56,11 +62,15 @@ impl Init {
|
|||
} = self;
|
||||
|
||||
pollee.invalidate();
|
||||
|
||||
let cred = SocketCred::<ReadOp>::new_current();
|
||||
let (this_conn, peer_conn) = Connected::new_pair(
|
||||
addr,
|
||||
Some(peer_addr),
|
||||
EndpointState::new(pollee, is_read_shutdown.into_inner()),
|
||||
EndpointState::new(Pollee::new(), is_write_shutdown.into_inner()),
|
||||
cred,
|
||||
peer_cred,
|
||||
);
|
||||
|
||||
(this_conn, peer_conn)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
|
||||
use aster_rights::ReadDupOp;
|
||||
use ostd::sync::WaitQueue;
|
||||
|
||||
use super::{
|
||||
|
|
@ -16,6 +17,7 @@ use crate::{
|
|||
net::socket::{
|
||||
unix::{
|
||||
addr::{UnixSocketAddrBound, UnixSocketAddrKey},
|
||||
cred::SocketCred,
|
||||
stream::socket::OptionSet,
|
||||
},
|
||||
util::{SockShutdownCmd, SocketAddr},
|
||||
|
|
@ -87,6 +89,10 @@ impl Listener {
|
|||
pub(super) fn check_io_events(&self) -> IoEvents {
|
||||
self.backlog.check_io_events()
|
||||
}
|
||||
|
||||
pub(super) fn cred(&self) -> &SocketCred<ReadDupOp> {
|
||||
&self.backlog.listener_cred
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Listener {
|
||||
|
|
@ -146,6 +152,7 @@ pub(super) struct Backlog {
|
|||
backlog: AtomicUsize,
|
||||
incoming_conns: SpinLock<Option<VecDeque<Connected>>>,
|
||||
wait_queue: WaitQueue,
|
||||
listener_cred: SocketCred<ReadDupOp>,
|
||||
}
|
||||
|
||||
impl Backlog {
|
||||
|
|
@ -162,6 +169,7 @@ impl Backlog {
|
|||
backlog: AtomicUsize::new(backlog),
|
||||
incoming_conns: SpinLock::new(incoming_sockets),
|
||||
wait_queue: WaitQueue::new(),
|
||||
listener_cred: SocketCred::<ReadDupOp>::new_current(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +256,11 @@ impl Backlog {
|
|||
));
|
||||
}
|
||||
|
||||
let (client_conn, server_conn) = init.into_connected(self.addr.clone(), pollee);
|
||||
let (client_conn, server_conn) = init.into_connected(
|
||||
self.addr.clone(),
|
||||
pollee,
|
||||
self.listener_cred.dup().restrict(),
|
||||
);
|
||||
|
||||
incoming_conns.push_back(server_conn);
|
||||
self.pollee.notify(IoEvents::IN);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use aster_rights::ReadDupOp;
|
||||
use takeable::Takeable;
|
||||
|
||||
use super::{
|
||||
|
|
@ -12,10 +13,11 @@ use super::{
|
|||
use crate::{
|
||||
events::IoEvents,
|
||||
fs::{file_handle::FileLike, utils::EndpointState},
|
||||
match_sock_option_mut,
|
||||
net::socket::{
|
||||
options::SocketOption,
|
||||
options::{PeerCred, PeerGroups, SocketOption},
|
||||
private::SocketPrivate,
|
||||
unix::UnixSocketAddr,
|
||||
unix::{cred::SocketCred, CUserCred, UnixSocketAddr},
|
||||
util::{
|
||||
options::{GetSocketLevelOption, SetSocketLevelOption, SocketOptionSet},
|
||||
MessageHeader, SendRecvFlags, SockShutdownCmd, SocketAddr,
|
||||
|
|
@ -23,7 +25,10 @@ use crate::{
|
|||
Socket,
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable, Pollee},
|
||||
process::{
|
||||
signal::{PollHandle, Pollable, Pollee},
|
||||
Gid,
|
||||
},
|
||||
util::{MultiRead, MultiWrite},
|
||||
};
|
||||
|
||||
|
|
@ -115,6 +120,24 @@ impl State {
|
|||
State::Connected(connected) => connected.is_write_shutdown(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(self) fn peer_cred(&self) -> Option<CUserCred> {
|
||||
match self {
|
||||
Self::Init(_) => None,
|
||||
Self::Listen(listener) => Some(listener.cred().to_c_user_cred()),
|
||||
Self::Connected(connected) => Some(connected.peer_cred().to_c_user_cred()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(self) fn peer_groups(&self) -> Result<Arc<[Gid]>> {
|
||||
match self {
|
||||
State::Init(_) => {
|
||||
return_errno_with_message!(Errno::ENODATA, "the socket does not have peer groups")
|
||||
}
|
||||
State::Listen(listener) => Ok(listener.cred().groups()),
|
||||
State::Connected(connected) => Ok(connected.peer_cred().groups()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -136,11 +159,15 @@ impl UnixStreamSocket {
|
|||
}
|
||||
|
||||
pub fn new_pair(is_nonblocking: bool) -> (Arc<Self>, Arc<Self>) {
|
||||
let cred = SocketCred::<ReadDupOp>::new_current();
|
||||
|
||||
let (conn_a, conn_b) = Connected::new_pair(
|
||||
None,
|
||||
None,
|
||||
EndpointState::default(),
|
||||
EndpointState::default(),
|
||||
cred.dup().restrict(),
|
||||
cred.restrict(),
|
||||
);
|
||||
let options = OptionSet::new();
|
||||
(
|
||||
|
|
@ -378,6 +405,12 @@ impl Socket for UnixStreamSocket {
|
|||
let state = self.state.read();
|
||||
let options = self.options.read();
|
||||
|
||||
// Deal with UNIX-socket-specific socket-level options
|
||||
match do_unix_getsockopt(option, state.as_ref()) {
|
||||
Err(err) if err.error() == Errno::ENOPROTOOPT => (),
|
||||
res => return res,
|
||||
}
|
||||
|
||||
// Deal with socket-level options
|
||||
match options.socket.get_option(option, state.as_ref()) {
|
||||
Err(err) if err.error() == Errno::ENOPROTOOPT => (),
|
||||
|
|
@ -409,6 +442,22 @@ impl Socket for UnixStreamSocket {
|
|||
}
|
||||
}
|
||||
|
||||
fn do_unix_getsockopt(option: &mut dyn SocketOption, state: &State) -> Result<()> {
|
||||
match_sock_option_mut!(option, {
|
||||
socket_peer_cred: PeerCred => {
|
||||
let peer_cred = state.peer_cred().unwrap_or_else(CUserCred::new_unknown);
|
||||
socket_peer_cred.set(peer_cred);
|
||||
},
|
||||
socket_peer_groups: PeerGroups => {
|
||||
let groups = state.peer_groups()?;
|
||||
socket_peer_groups.set(groups);
|
||||
},
|
||||
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "the socket option to get is not unix socket specific")
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl GetSocketLevelOption for State {
|
||||
fn is_listening(&self) -> bool {
|
||||
matches!(self, Self::Listen(_))
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ use crate::{
|
|||
match_sock_option_mut, match_sock_option_ref,
|
||||
net::socket::{
|
||||
options::{
|
||||
AcceptConn, KeepAlive, Linger, Priority, RecvBuf, RecvBufForce, ReuseAddr, ReusePort,
|
||||
SendBuf, SendBufForce, SocketOption,
|
||||
AcceptConn, KeepAlive, Linger, PeerCred, PeerGroups, Priority, RecvBuf, RecvBufForce,
|
||||
ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption,
|
||||
},
|
||||
unix::UNIX_STREAM_DEFAULT_BUF_SIZE,
|
||||
unix::{CUserCred, UNIX_STREAM_DEFAULT_BUF_SIZE},
|
||||
},
|
||||
prelude::*,
|
||||
process::{credentials::capabilities::CapSet, posix_thread::AsPosixThread},
|
||||
|
|
@ -114,6 +114,10 @@ impl SocketOptionSet {
|
|||
let keep_alive = self.keep_alive();
|
||||
socket_keepalive.set(keep_alive);
|
||||
},
|
||||
socket_peer_cred: PeerCred => {
|
||||
let peer_cred = CUserCred::new_unknown();
|
||||
socket_peer_cred.set(peer_cred);
|
||||
},
|
||||
socket_accept_conn: AcceptConn => {
|
||||
let is_listening = socket.is_listening();
|
||||
socket_accept_conn.set(is_listening);
|
||||
|
|
@ -128,6 +132,9 @@ impl SocketOptionSet {
|
|||
let recv_buf = self.recv_buf();
|
||||
socket_recvbuf_force.set(recv_buf);
|
||||
},
|
||||
_socket_peer_groups: PeerGroups => {
|
||||
return_errno_with_message!(Errno::ENODATA, "the socket does not have peer groups");
|
||||
},
|
||||
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "the socket option to get is unknown")
|
||||
});
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ use crate::prelude::*;
|
|||
pub struct Gid(u32);
|
||||
|
||||
impl Gid {
|
||||
/// The invalid GID, typically used to indicate that no valid GID is found when returning to user space.
|
||||
///
|
||||
/// Reference: <https://elixir.bootlin.com/linux/v6.15/source/include/linux/uidgid.h#L51>.
|
||||
pub const INVALID: Gid = Gid(u32::MAX);
|
||||
|
||||
pub const fn new(gid: u32) -> Self {
|
||||
Self(gid)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ pub struct Uid(u32);
|
|||
const ROOT_UID: u32 = 0;
|
||||
|
||||
impl Uid {
|
||||
/// The invalid UID, typically used to indicate that no valid UID is found when returning to user space.
|
||||
///
|
||||
/// Reference: <https://elixir.bootlin.com/linux/v6.15/source/include/linux/uidgid.h#L50>.
|
||||
pub const INVALID: Uid = Self::new(u32::MAX);
|
||||
|
||||
pub const fn new_root() -> Self {
|
||||
Self(ROOT_UID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use aster_rights::{ReadOp, WriteOp};
|
||||
use aster_rights::{ReadDupOp, ReadOp, WriteOp};
|
||||
use ostd::sync::{RoArc, Waker};
|
||||
|
||||
use super::{
|
||||
|
|
@ -291,6 +291,11 @@ impl PosixThread {
|
|||
self.credentials.dup().restrict()
|
||||
}
|
||||
|
||||
/// Gets the duplicatable read-only credentials of the thread.
|
||||
pub fn credentials_dup(&self) -> Credentials<ReadDupOp> {
|
||||
self.credentials.dup().restrict()
|
||||
}
|
||||
|
||||
/// Gets the write-only credentials of the current thread.
|
||||
///
|
||||
/// It is illegal to mutate the credentials from a thread other than the
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ pub fn sys_getsockopt(
|
|||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
let level = CSocketOptionLevel::try_from(level).map_err(|_| Errno::EOPNOTSUPP)?;
|
||||
if optval == 0 || optlen_addr == 0 {
|
||||
return_errno_with_message!(Errno::EINVAL, "optval or optlen_addr is null pointer");
|
||||
if optlen_addr == 0 {
|
||||
return_errno_with_message!(Errno::EINVAL, "optlen_addr is null pointer");
|
||||
}
|
||||
|
||||
let user_space = ctx.user_space();
|
||||
|
|
@ -34,7 +34,14 @@ pub fn sys_getsockopt(
|
|||
|
||||
socket.get_option(raw_option.as_sock_option_mut())?;
|
||||
|
||||
let write_len = raw_option.write_to_user(optval, optlen)?;
|
||||
let write_len = {
|
||||
let mut new_opt_len = optlen;
|
||||
let res = raw_option.write_to_user(optval, &mut new_opt_len);
|
||||
if new_opt_len != optlen {
|
||||
user_space.write_val(optlen_addr, &new_opt_len)?;
|
||||
}
|
||||
res?
|
||||
};
|
||||
user_space.write_val(optlen_addr, &(write_len as u32))?;
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ use self::{socket::new_socket_option, tcp::new_tcp_option};
|
|||
pub trait RawSocketOption: SocketOption {
|
||||
fn read_from_user(&mut self, addr: Vaddr, max_len: u32) -> Result<()>;
|
||||
|
||||
fn write_to_user(&self, addr: Vaddr, max_len: u32) -> Result<usize>;
|
||||
fn write_to_user(&self, addr: Vaddr, max_len: &mut u32) -> Result<usize>;
|
||||
|
||||
fn as_sock_option_mut(&mut self) -> &mut dyn SocketOption;
|
||||
|
||||
|
|
@ -87,11 +87,11 @@ macro_rules! impl_raw_socket_option {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_to_user(&self, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
fn write_to_user(&self, addr: Vaddr, max_len: &mut u32) -> Result<usize> {
|
||||
use $crate::util::net::options::utils::WriteToUser;
|
||||
|
||||
let output = self.get().unwrap();
|
||||
output.write_to_user(addr, max_len)
|
||||
output.write_to_user(addr, *max_len)
|
||||
}
|
||||
|
||||
fn as_sock_option_mut(&mut self) -> &mut dyn SocketOption {
|
||||
|
|
@ -114,11 +114,11 @@ macro_rules! impl_raw_sock_option_get_only {
|
|||
return_errno_with_message!(Errno::ENOPROTOOPT, "the option is getter-only");
|
||||
}
|
||||
|
||||
fn write_to_user(&self, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
fn write_to_user(&self, addr: Vaddr, max_len: &mut u32) -> Result<usize> {
|
||||
use $crate::util::net::options::utils::WriteToUser;
|
||||
|
||||
let output = self.get().unwrap();
|
||||
output.write_to_user(addr, max_len)
|
||||
output.write_to_user(addr, *max_len)
|
||||
}
|
||||
|
||||
fn as_sock_option_mut(&mut self) -> &mut dyn SocketOption {
|
||||
|
|
@ -145,7 +145,7 @@ macro_rules! impl_raw_sock_option_set_only {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_to_user(&self, _addr: Vaddr, _max_len: u32) -> Result<usize> {
|
||||
fn write_to_user(&self, _addr: Vaddr, _max_len: &mut u32) -> Result<usize> {
|
||||
return_errno_with_message!(Errno::ENOPROTOOPT, "the option is setter-only");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
use super::RawSocketOption;
|
||||
use crate::{
|
||||
impl_raw_sock_option_get_only, impl_raw_socket_option,
|
||||
current_userspace, impl_raw_sock_option_get_only, impl_raw_socket_option,
|
||||
net::socket::options::{
|
||||
AcceptConn, Error, KeepAlive, Linger, Priority, RecvBuf, RecvBufForce, ReuseAddr,
|
||||
ReusePort, SendBuf, SendBufForce, SocketOption,
|
||||
AcceptConn, Error, KeepAlive, Linger, PeerCred, PeerGroups, Priority, RecvBuf,
|
||||
RecvBufForce, ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption,
|
||||
},
|
||||
prelude::*,
|
||||
process::Gid,
|
||||
};
|
||||
|
||||
/// Socket level options.
|
||||
|
|
@ -33,9 +34,15 @@ enum CSocketOptionName {
|
|||
LINGER = 13,
|
||||
BSDCOMPAT = 14,
|
||||
REUSEPORT = 15,
|
||||
PASSCRED = 16,
|
||||
PEERCRED = 17,
|
||||
ATTACH_FILTER = 26,
|
||||
DETACH_FILTER = 27,
|
||||
ACCPETCONN = 30,
|
||||
PEERSEC = 31,
|
||||
SNDBUFFORCE = 32,
|
||||
RCVBUFFORCE = 33,
|
||||
PEERGROUPS = 59,
|
||||
RCVTIMEO_NEW = 66,
|
||||
SNDTIMEO_NEW = 67,
|
||||
}
|
||||
|
|
@ -51,9 +58,11 @@ pub fn new_socket_option(name: i32) -> Result<Box<dyn RawSocketOption>> {
|
|||
CSocketOptionName::PRIORITY => Ok(Box::new(Priority::new())),
|
||||
CSocketOptionName::LINGER => Ok(Box::new(Linger::new())),
|
||||
CSocketOptionName::KEEPALIVE => Ok(Box::new(KeepAlive::new())),
|
||||
CSocketOptionName::PEERCRED => Ok(Box::new(PeerCred::new())),
|
||||
CSocketOptionName::ACCPETCONN => Ok(Box::new(AcceptConn::new())),
|
||||
CSocketOptionName::SNDBUFFORCE => Ok(Box::new(SendBufForce::new())),
|
||||
CSocketOptionName::RCVBUFFORCE => Ok(Box::new(RecvBufForce::new())),
|
||||
CSocketOptionName::PEERGROUPS => Ok(Box::new(PeerGroups::new())),
|
||||
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "unsupported socket-level option"),
|
||||
}
|
||||
}
|
||||
|
|
@ -66,6 +75,40 @@ impl_raw_socket_option!(ReusePort);
|
|||
impl_raw_socket_option!(Priority);
|
||||
impl_raw_socket_option!(Linger);
|
||||
impl_raw_socket_option!(KeepAlive);
|
||||
impl_raw_sock_option_get_only!(PeerCred);
|
||||
impl_raw_sock_option_get_only!(AcceptConn);
|
||||
impl_raw_socket_option!(SendBufForce);
|
||||
impl_raw_socket_option!(RecvBufForce);
|
||||
|
||||
// SO_PEERGROUPS is a read-only option. However, calling setsockopt on SO_PEERGROUPS will return EINVAL
|
||||
// instead of ENOPROTOOPT like other options. Therefore, we manually implement `RawSocketOption` for it.
|
||||
impl RawSocketOption for PeerGroups {
|
||||
fn read_from_user(&mut self, _addr: Vaddr, _max_len: u32) -> Result<()> {
|
||||
return_errno_with_message!(Errno::EINVAL, "the option is getter-only");
|
||||
}
|
||||
|
||||
fn write_to_user(&self, addr: Vaddr, buffer_len: &mut u32) -> Result<usize> {
|
||||
let groups = self.get().unwrap();
|
||||
|
||||
let old_len = *buffer_len;
|
||||
*buffer_len = (groups.len() * core::mem::size_of::<Gid>()) as u32;
|
||||
if old_len < *buffer_len {
|
||||
return_errno_with_message!(Errno::ERANGE, "the buffer is too small");
|
||||
}
|
||||
|
||||
for (i, gid) in groups.iter().enumerate() {
|
||||
let dst = addr + i * core::mem::size_of::<Gid>();
|
||||
current_userspace!().write_val(dst, gid)?;
|
||||
}
|
||||
|
||||
Ok(*buffer_len as usize)
|
||||
}
|
||||
|
||||
fn as_sock_option_mut(&mut self) -> &mut dyn SocketOption {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_sock_option(&self) -> &dyn SocketOption {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use crate::{
|
|||
current_userspace,
|
||||
net::socket::{
|
||||
ip::{options::IpTtl, stream_options::CongestionControl},
|
||||
unix::CUserCred,
|
||||
util::LingerOption,
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -225,3 +226,17 @@ impl From<CLinger> for LingerOption {
|
|||
LingerOption::new(is_on, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteToUser for CUserCred {
|
||||
fn write_to_user(&self, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
let write_len = core::mem::size_of::<CUserCred>();
|
||||
|
||||
if (max_len as usize) < write_len {
|
||||
return_errno_with_message!(Errno::EINVAL, "max_len is too short");
|
||||
};
|
||||
|
||||
current_userspace!().write_val(addr, self)?;
|
||||
|
||||
Ok(write_len)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue