Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ linux-raw-sys = { version = "0.11", default-features = false, features = [
"net",
"prctl",
"system",
"netlink",
] }
memory_addr = "0.4"
scope-local = "0.1"
Expand Down Expand Up @@ -98,6 +99,9 @@ qemu = [
"axfeat/vsock",
"starry-api/vsock",

"axfeat/netlink",
"starry-api/netlink",

"axfeat/defplat",
"axfeat/bus-pci",

Expand Down
1 change: 1 addition & 0 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ repository.workspace = true
input = ["dep:axinput"]
memtrack = ["axfeat/dwarf", "axalloc/tracking", "dep:gimli"]
vsock = ["axnet/vsock"]
netlink = ["axnet/netlink"]
dev-log = []

[dependencies]
Expand Down
16 changes: 16 additions & 0 deletions api/src/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,22 @@ pub fn close_file_like(fd: c_int) -> AxResult {
Ok(())
}

pub fn get_cloexec(fd: c_int) -> AxResult<bool> {
FD_TABLE
.read()
.get(fd as usize)
.ok_or(AxError::BadFileDescriptor)
.map(|fd| fd.cloexec)
}

pub fn set_cloexec(fd: c_int, cloexec: bool) -> AxResult {
FD_TABLE
.write()
.get_mut(fd as usize)
.ok_or(AxError::BadFileDescriptor)
.map(|fd| fd.cloexec = cloexec)
}

pub fn add_stdio(fd_table: &mut FlattenObjects<FileDescriptor, AX_FILE_LIMIT>) -> AxResult<()> {
assert_eq!(fd_table.count(), 0);
let cx = FS_CONTEXT.lock();
Expand Down
40 changes: 40 additions & 0 deletions api/src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ use core::{
};

use axerrno::{AxError, AxResult, LinuxError};
#[cfg(feature = "netlink")]
use axnet::netlink::{GroupIdSet, NetlinkSocketAddr};
#[cfg(feature = "vsock")]
use axnet::vsock::VsockAddr;
use axnet::{SocketAddrEx, unix::UnixSocketAddr};
use linux_raw_sys::net::*;
#[cfg(feature = "netlink")]
use linux_raw_sys::netlink::sockaddr_nl;

use crate::mm::{UserConstPtr, UserPtr};

Expand Down Expand Up @@ -241,11 +245,45 @@ impl SocketAddrExt for VsockAddr {
}
}

#[cfg(feature = "netlink")]
impl SocketAddrExt for NetlinkSocketAddr {
fn read_from_user(addr: UserConstPtr<sockaddr>, addrlen: socklen_t) -> AxResult<Self> {
if addrlen != size_of::<sockaddr_nl>() as socklen_t {
return Err(AxError::InvalidInput);
}
let addr_nl = addr.cast::<sockaddr_nl>().get_as_ref()?;
if addr_nl.nl_family as u32 != AF_NETLINK {
return Err(AxError::from(LinuxError::EAFNOSUPPORT));
}

Ok(NetlinkSocketAddr::new(
addr_nl.nl_pid,
GroupIdSet::new(addr_nl.nl_groups),
))
}

fn write_to_user(&self, addr: UserPtr<sockaddr>, addrlen: &mut socklen_t) -> AxResult<()> {
let socknl_addr = sockaddr_nl {
nl_family: AF_NETLINK as _,
nl_pad: 0,
nl_pid: self.port(),
nl_groups: self.groups().as_u32(),
};
fill_addr(addr, addrlen, unsafe { cast_to_slice(&socknl_addr) })
}

fn family(&self) -> u16 {
AF_NETLINK as u16
}
}

impl SocketAddrExt for SocketAddrEx {
fn read_from_user(addr: UserConstPtr<sockaddr>, addrlen: socklen_t) -> AxResult<Self> {
match read_family(addr, addrlen)? as u32 {
AF_INET | AF_INET6 => SocketAddr::read_from_user(addr, addrlen).map(Self::Ip),
AF_UNIX => UnixSocketAddr::read_from_user(addr, addrlen).map(Self::Unix),
#[cfg(feature = "netlink")]
AF_NETLINK => NetlinkSocketAddr::read_from_user(addr, addrlen).map(Self::Netlink),
#[cfg(feature = "vsock")]
AF_VSOCK => VsockAddr::read_from_user(addr, addrlen).map(Self::Vsock),
_ => Err(AxError::from(LinuxError::EAFNOSUPPORT)),
Expand All @@ -256,6 +294,8 @@ impl SocketAddrExt for SocketAddrEx {
match self {
SocketAddrEx::Ip(ip_addr) => ip_addr.write_to_user(addr, addrlen),
SocketAddrEx::Unix(unix_addr) => unix_addr.write_to_user(addr, addrlen),
#[cfg(feature = "netlink")]
SocketAddrEx::Netlink(netlink_addr) => netlink_addr.write_to_user(addr, addrlen),
#[cfg(feature = "vsock")]
SocketAddrEx::Vsock(vsock_addr) => vsock_addr.write_to_user(addr, addrlen),
}
Expand Down
54 changes: 32 additions & 22 deletions api/src/syscall/fs/ctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,42 +12,52 @@ use axhal::time::wall_time;
use axtask::current;
use linux_raw_sys::{
general::*,
ioctl::{FIONBIO, TIOCGWINSZ},
ioctl::{FIOCLEX, FIONBIO, FIONCLEX, TCGETS, TIOCGWINSZ},
};
use starry_core::task::AsThread;
use starry_vm::{VmPtr, vm_write_slice};

use crate::{
file::{Directory, FileLike, get_file_like, resolve_at, with_fs},
file::{Directory, FileLike, get_file_like, resolve_at, set_cloexec, with_fs},
mm::vm_load_string,
time::TimeValueLike,
};

/// The ioctl() system call manipulates the underlying device parameters
/// of special files.
pub fn sys_ioctl(fd: i32, cmd: u32, arg: usize) -> AxResult<isize> {
debug!("sys_ioctl <= fd: {fd}, cmd: {cmd}, arg: {arg}");
let f = get_file_like(fd)?;
if cmd == FIONBIO {
let val = (arg as *const u8).vm_read()?;
if val != 0 && val != 1 {
return Err(AxError::InvalidInput);
debug!("sys_ioctl <= fd: {}, cmd: {}, arg: {}", fd, cmd, arg);
match cmd {
FIONBIO => {
let val = (arg as *const u8).vm_read()?;
if val > 1 {
return Err(AxError::InvalidInput);
}
get_file_like(fd)?.set_nonblocking(val != 0)?;
Ok(0)
}
f.set_nonblocking(val != 0)?;
return Ok(0);
}
f.ioctl(cmd, arg)
.map(|result| result as isize)
.inspect_err(|err| {
if *err == AxError::NotATty {
// glibc likes to call TIOCGWINSZ on non-terminal files, just
// ignore it
if cmd == TIOCGWINSZ {
return;
FIOCLEX => {
set_cloexec(fd, true)?;
Ok(0)
}
FIONCLEX => {
set_cloexec(fd, false)?;
Ok(0)
}
_ => get_file_like(fd)?
.ioctl(cmd, arg)
.map(|result| result as isize)
.inspect_err(|err| {
if *err == AxError::NotATty {
// glibc likes to call TIOCGWINSZ and TCGETS on non-terminal files, just
// ignore it
if cmd == TIOCGWINSZ || cmd == TCGETS {
return;
}
warn!("Unsupported ioctl command: {cmd} for fd: {fd}");
}
warn!("Unsupported ioctl command: {cmd} for fd: {fd}");
}
})
}),
}
}

pub fn sys_chdir(path: *const c_char) -> AxResult<isize> {
Expand Down
16 changes: 4 additions & 12 deletions api/src/syscall/fs/fd_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use starry_core::{task::AsThread, vfs::Device};

use crate::{
file::{
Directory, FD_TABLE, File, FileLike, Pipe, add_file_like, close_file_like, get_file_like,
with_fs,
Directory, FD_TABLE, File, FileLike, Pipe, add_file_like, close_file_like, get_cloexec,
get_file_like, set_cloexec, with_fs,
},
mm::{UserPtr, vm_load_string},
syscall::sys::{sys_getegid, sys_geteuid},
Expand Down Expand Up @@ -273,20 +273,12 @@ pub fn sys_fcntl(fd: c_int, cmd: c_int, arg: usize) -> AxResult<isize> {
Ok(ret as _)
}
F_GETFD => {
let cloexec = FD_TABLE
.read()
.get(fd as _)
.ok_or(AxError::BadFileDescriptor)?
.cloexec;
let cloexec = get_cloexec(fd)?;
Ok(if cloexec { FD_CLOEXEC as _ } else { 0 })
}
F_SETFD => {
let cloexec = arg & FD_CLOEXEC as usize != 0;
FD_TABLE
.write()
.get_mut(fd as _)
.ok_or(AxError::BadFileDescriptor)?
.cloexec = cloexec;
set_cloexec(fd, cloexec)?;
Ok(0)
}
F_GETPIPE_SZ => {
Expand Down
14 changes: 14 additions & 0 deletions api/src/syscall/net/socket.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use axerrno::{AxError, AxResult, LinuxError};
#[cfg(feature = "netlink")]
use axnet::netlink::RouteTransport;
#[cfg(feature = "vsock")]
use axnet::vsock::{VsockSocket, VsockStreamTransport};
use axnet::{
Expand All @@ -15,6 +17,11 @@ use linux_raw_sys::{
SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM, sockaddr, socklen_t,
},
};
#[cfg(feature = "netlink")]
use linux_raw_sys::{
net::{AF_NETLINK, SOCK_RAW},
netlink::NETLINK_ROUTE,
};
use starry_core::task::AsThread;

use crate::{
Expand Down Expand Up @@ -47,6 +54,13 @@ pub fn sys_socket(domain: u32, raw_ty: u32, proto: u32) -> AxResult<isize> {
(AF_VSOCK, SOCK_STREAM) => {
axnet::Socket::Vsock(VsockSocket::new(VsockStreamTransport::new()))
}
#[cfg(feature = "netlink")]
(AF_NETLINK, SOCK_RAW | SOCK_DGRAM) => {
if proto != NETLINK_ROUTE as _ {
return Err(AxError::from(LinuxError::EPROTONOSUPPORT));
}
axnet::Socket::Netlink(axnet::netlink::NetlinkSocket::new(RouteTransport::new()))
}
(AF_INET, _) | (AF_UNIX, _) | (AF_VSOCK, _) => {
warn!("Unsupported socket type: domain: {domain}, ty: {ty}");
return Err(AxError::from(LinuxError::ESOCKTNOSUPPORT));
Expand Down
2 changes: 1 addition & 1 deletion api/src/syscall/task/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fn sys_getpgid(pid: Pid) -> AxResult<isize> {
pub fn sys_setpgid(pid: Pid, pgid: Pid) -> AxResult<isize> {
let proc = &get_process_data(pid)?.proc;

if pgid == 0 {
if pgid == 0 || pgid == proc.pid() {
proc.create_group();
} else if !proc.move_to_group(&get_process_group(pgid)?) {
return Err(AxError::OperationNotPermitted);
Expand Down