diff --git a/kernel/src/net/socket/options/mod.rs b/kernel/src/net/socket/options/mod.rs index 9eeed359f..d5c164045 100644 --- a/kernel/src/net/socket/options/mod.rs +++ b/kernel/src/net/socket/options/mod.rs @@ -21,6 +21,7 @@ impl_socket_options!( pub struct Priority(i32); pub struct Linger(LingerOption); pub struct KeepAlive(bool); + pub struct PassCred(bool); pub struct PeerCred(CUserCred); pub struct AcceptConn(bool); pub struct SendBufForce(u32); diff --git a/kernel/src/net/socket/util/options.rs b/kernel/src/net/socket/util/options.rs index de045e77d..65d0d869a 100644 --- a/kernel/src/net/socket/util/options.rs +++ b/kernel/src/net/socket/util/options.rs @@ -11,8 +11,8 @@ use crate::{ match_sock_option_mut, match_sock_option_ref, net::socket::{ options::{ - AcceptConn, KeepAlive, Linger, PeerCred, PeerGroups, Priority, RecvBuf, RecvBufForce, - ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption, + AcceptConn, KeepAlive, Linger, PassCred, PeerCred, PeerGroups, Priority, RecvBuf, + RecvBufForce, ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption, }, unix::{CUserCred, UNIX_STREAM_DEFAULT_BUF_SIZE}, }, @@ -30,6 +30,7 @@ pub struct SocketOptionSet { recv_buf: u32, linger: LingerOption, keep_alive: bool, + pass_cred: bool, priority: i32, } @@ -42,14 +43,15 @@ impl Default for SocketOptionSet { recv_buf: MIN_RECVBUF, linger: LingerOption::default(), keep_alive: false, + pass_cred: false, priority: 0, } } } impl SocketOptionSet { - /// Return the default socket level options for tcp socket. - pub fn new_tcp() -> Self { + /// Returns the default socket level options for tcp socket. + pub(in crate::net) fn new_tcp() -> Self { Self { send_buf: TCP_SEND_BUF_LEN as u32, recv_buf: TCP_RECV_BUF_LEN as u32, @@ -57,8 +59,8 @@ impl SocketOptionSet { } } - /// Return the default socket level options for udp socket. - pub fn new_udp() -> Self { + /// Returns the default socket level options for udp socket. + pub(in crate::net) fn new_udp() -> Self { Self { send_buf: UDP_SEND_PAYLOAD_LEN as u32, recv_buf: UDP_RECV_PAYLOAD_LEN as u32, @@ -114,6 +116,12 @@ impl SocketOptionSet { let keep_alive = self.keep_alive(); socket_keepalive.set(keep_alive); }, + socket_pass_cred: PassCred => { + // This option only affects UNIX sockets. However, it also works well with other + // sockets for setting and getting. + let pass_cred = self.pass_cred(); + socket_pass_cred.set(pass_cred); + }, socket_peer_cred: PeerCred => { let peer_cred = CUserCred::new_unknown(); socket_peer_cred.set(peer_cred); @@ -185,6 +193,12 @@ impl SocketOptionSet { self.set_keep_alive(*keep_alive); return Ok(socket.set_keep_alive(*keep_alive)); }, + socket_pass_cred: PassCred => { + // This option only affects UNIX sockets. However, it also works well with other + // sockets for setting and getting. + let pass_cred = socket_pass_cred.get().unwrap(); + self.set_pass_cred(*pass_cred); + }, socket_sendbuf_force: SendBufForce => { check_current_privileged()?; let send_buf = socket_sendbuf_force.get().unwrap(); diff --git a/kernel/src/util/net/options/socket.rs b/kernel/src/util/net/options/socket.rs index fd3de31e2..43e1c5b70 100644 --- a/kernel/src/util/net/options/socket.rs +++ b/kernel/src/util/net/options/socket.rs @@ -4,7 +4,7 @@ use super::RawSocketOption; use crate::{ current_userspace, impl_raw_sock_option_get_only, impl_raw_socket_option, net::socket::options::{ - AcceptConn, Error, KeepAlive, Linger, PeerCred, PeerGroups, Priority, RecvBuf, + AcceptConn, Error, KeepAlive, Linger, PassCred, PeerCred, PeerGroups, Priority, RecvBuf, RecvBufForce, ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption, }, prelude::*, @@ -57,6 +57,7 @@ pub fn new_socket_option(name: i32) -> Result> { CSocketOptionName::REUSEPORT => Ok(Box::new(ReusePort::new())), CSocketOptionName::PRIORITY => Ok(Box::new(Priority::new())), CSocketOptionName::LINGER => Ok(Box::new(Linger::new())), + CSocketOptionName::PASSCRED => Ok(Box::new(PassCred::new())), CSocketOptionName::KEEPALIVE => Ok(Box::new(KeepAlive::new())), CSocketOptionName::PEERCRED => Ok(Box::new(PeerCred::new())), CSocketOptionName::ACCPETCONN => Ok(Box::new(AcceptConn::new())), @@ -75,6 +76,7 @@ impl_raw_socket_option!(ReusePort); impl_raw_socket_option!(Priority); impl_raw_socket_option!(Linger); impl_raw_socket_option!(KeepAlive); +impl_raw_socket_option!(PassCred); impl_raw_sock_option_get_only!(PeerCred); impl_raw_sock_option_get_only!(AcceptConn); impl_raw_socket_option!(SendBufForce); diff --git a/test/src/apps/network/sockoption_unix.c b/test/src/apps/network/sockoption_unix.c index a6df746b2..543f9fc35 100644 --- a/test/src/apps/network/sockoption_unix.c +++ b/test/src/apps/network/sockoption_unix.c @@ -4,7 +4,6 @@ * UNIX stream socket-related socket options. */ -#include #include #include #include @@ -83,6 +82,37 @@ FN_TEST(acceptconn) } END_TEST() +FN_TEST(pass_cred) +{ + int val = 0; + socklen_t len = sizeof(val); + + TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PASSCRED, &val, &len), + len == 4 && val == 0); + TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_PASSCRED, &val, &len), + len == 4 && val == 0); + TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_PASSCRED, &val, &len), + len == 4 && val == 0); + TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_PASSCRED, &val, &len), + len == 4 && val == 0); + + val = 100; + TEST_SUCC(setsockopt(sk_tcp, SOL_SOCKET, SO_PASSCRED, &val, len)); + TEST_SUCC(setsockopt(sk_unbound, SOL_SOCKET, SO_PASSCRED, &val, len)); + TEST_SUCC(setsockopt(sk_listen, SOL_SOCKET, SO_PASSCRED, &val, len)); + TEST_SUCC(setsockopt(sk_connected, SOL_SOCKET, SO_PASSCRED, &val, len)); + + TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PASSCRED, &val, &len), + len == 4 && val == 1); + TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_PASSCRED, &val, &len), + len == 4 && val == 1); + TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_PASSCRED, &val, &len), + len == 4 && val == 1); + TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_PASSCRED, &val, &len), + len == 4 && val == 1); +} +END_TEST() + FN_TEST(peer_cred) { struct cred { @@ -94,7 +124,7 @@ FN_TEST(peer_cred) struct cred ucred = {}; socklen_t len = sizeof(ucred); - TEST_ERRNO(setsockopt(sk_unbound, SOL_SOCKET, SO_PEERCRED, &ucred, len), + TEST_ERRNO(setsockopt(sk_tcp, SOL_SOCKET, SO_PEERCRED, &ucred, len), ENOPROTOOPT); TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PEERCRED, &ucred, &len), ucred.pid == 0 && ucred.uid == -1 && ucred.gid == -1); @@ -228,4 +258,4 @@ FN_SETUP(cleanup) CHECK(close(sk_tcp)); CHECK(unlink(addr.sun_path)); } -END_SETUP() \ No newline at end of file +END_SETUP()