Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

readlink and readlinkat implementation on RawPOSIX / Wasmtime / glibc #76

Merged
merged 26 commits into from
Feb 6, 2025
Merged
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
Next Next commit
Add implementation of readlink and readlinkat to RawPOSIX and glibc
Yaxuan-w committed Jan 5, 2025
commit fa060860c5084a784855d0c05411a3bb07bfe85e
34 changes: 34 additions & 0 deletions src/RawPOSIX/src/safeposix/dispatcher.rs
Original file line number Diff line number Diff line change
@@ -111,6 +111,9 @@ const FSYNC_SYSCALL: i32 = 162;
const FDATASYNC_SYSCALL: i32 = 163;
const SYNC_FILE_RANGE: i32 = 164;

const READLINK_SYSCALL: i32 = 165;
const READLINKAT_SYSCALL: i32 = 166;

const WRITEV_SYSCALL: i32 = 170;

const CLONE_SYSCALL: i32 = 171;
@@ -119,6 +122,7 @@ const WAITPID_SYSCALL: i32 = 173;

const NANOSLEEP_TIME64_SYSCALL : i32 = 181;


use std::ffi::CString;
use std::ffi::CStr;
use super::cage::*;
@@ -1050,6 +1054,36 @@ pub fn lind_syscall_api(
.waitpid_syscall(pid, &mut status, options)
}

READLINK_SYSCALL => {
let path_ptr = (start_address + arg1) as *const u8;
let path = unsafe {
CStr::from_ptr(path_ptr as *const i8).to_str().unwrap()
};

let buf = (start_address + arg2) as *mut u8;

let buflen = arg3 as usize;

interface::cagetable_getref(cageid)
.readlink_syscall(path, buf, buflen)
}

READLINKAT_SYSCALL => {
let fd = arg1 as i32;

let path_ptr = (start_address + arg2) as *const u8;
let path = unsafe {
CStr::from_ptr(path_ptr as *const i8).to_str().unwrap()
};

let buf = (start_address + arg3) as *mut u8;

let buflen = arg4 as usize;

interface::cagetable_getref(cageid)
.readlinkat_syscall(fd, path, buf, buflen)
}

_ => -1, // Return -1 for unknown syscalls
};
ret
53 changes: 53 additions & 0 deletions src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs
Original file line number Diff line number Diff line change
@@ -370,6 +370,59 @@ impl Cage {

}

//------------------------------------READLINK and READLINKAT SYSCALL------------------------------------
/*
* readlink() places the contents of the symbolic link pathname in
the buffer buf, which has size bufsiz. readlink() does not
append a terminating null byte to buf. It will (silently)
truncate the contents (to a length of bufsiz characters), in case
the buffer is too small to hold all of the contents.

So we need to first
*/
pub fn readlink_syscall(&self, path: &str, buf: *mut u8, buflen: usize) -> i32 {
// Convert the path from relative path (lind-wasm perspective) to real kernel path (host kernel
// perspective)
let relpath = normpath(convpath(path), self);
let relative_path = relpath.to_str().unwrap();
let full_path = format!("{}{}", LIND_ROOT, relative_path);
let c_path = CString::new(full_path).unwrap();

let libcret = unsafe {
libc::readlink(c_path.as_ptr(), buf as *mut c_char, buflen)
};

if libcret < 0 {
let errno = get_errno();
return handle_errno(errno, "readlink");
}

}

pub fn readlinkat_syscall(&self, virtual_fd: i32, path: &str, buf: *mut u8, buflen: usize) -> i32 {
// Convert the virtual fd into real kernel fd and handle the error case
let wrappedvfd = fdtables::translate_virtual_fd(self.cageid, virtual_fd as u64);
if wrappedvfd.is_err() {
return syscall_error(Errno::EBADF, "readlinkat", "Bad File Descriptor");
}
let vfd = wrappedvfd.unwrap();
// Convert the path from relative path (lind-wasm perspective) to real kernel path (host kernel
// perspective)
let relpath = normpath(convpath(path), self);
let relative_path = relpath.to_str().unwrap();
let full_path = format!("{}{}", LIND_ROOT, relative_path);
let c_path = CString::new(full_path).unwrap();

let libcret = unsafe {
libc::readlinkat(vfd.underfd as i32, c_path.as_ptr(), buf as *mut c_char, buflen)
};

if libcret < 0 {
let errno = get_errno();
return handle_errno(errno, "readlinkat");
}
}

//------------------------------------WRITE SYSCALL------------------------------------
/*
* Get the kernel fd with provided virtual fd first
3 changes: 2 additions & 1 deletion src/glibc/include/unistd.h
Original file line number Diff line number Diff line change
@@ -153,7 +153,8 @@ extern int __symlink (const char *__from, const char *__to);
extern int __symlinkat (const char *__from, int __fd, const char *__to);
extern ssize_t __readlink (const char *__path, char *__buf, size_t __len)
attribute_hidden;
extern ssize_t __readlinkat (int __fd, const char *__file_name, char *__buf, size_t __len);
extern ssize_t __readlinkat (int __fd, const char *__file_name, char *__buf, size_t __len)
attribute_hidden;
extern int __unlink (const char *__name) attribute_hidden;
extern int __unlinkat (int __fd, const char *__name, int __flag);
extern int __gethostname (char *__name, size_t __len) attribute_hidden;
3 changes: 2 additions & 1 deletion src/glibc/sysdeps/unix/syscalls.list
Original file line number Diff line number Diff line change
@@ -46,7 +46,8 @@ open - open Ci:siv __libc_open __open open
profil - profil i:piii __profil profil
ptrace - ptrace i:iiii ptrace
read - read Ci:ibU __libc_read __read read
readlink - readlink i:spU __readlink readlink
readlink - readlink i:spU __libc_readlink readlink
readlinkat - readlinkat i:spU __libc_readlinkat readlinkat
readv - readv Ci:ipi __readv readv
reboot - reboot i:i reboot
recv - recv Ci:ibUi __libc_recv recv
17 changes: 9 additions & 8 deletions src/glibc/sysdeps/unix/sysv/linux/readlink.c
Original file line number Diff line number Diff line change
@@ -18,18 +18,19 @@

#include <unistd.h>
#include <fcntl.h>
#include <sysdep.h>
#include <sysdep-cancel.h>
#include <syscall-template.h>

/* Read the contents of the symbolic link PATH into no more than
LEN bytes of BUF. The contents are not null-terminated.
Returns the number of characters read, or -1 for errors. */
/*
* Edit Note:
* We implement both `readlink` and `readlinkat` in RawPOSIX, so changed the normal
*/
ssize_t
__readlink (const char *path, char *buf, size_t len)
__libc_readlink (const char *path, char *buf, size_t len)
{
#ifdef __NR_readlink
return INLINE_SYSCALL_CALL (readlink, path, buf, len);
#else
return INLINE_SYSCALL_CALL (readlinkat, AT_FDCWD, path, buf, len);
#endif
return MAKE_SYSCALL(165, "syscall|readlink", (uint64_t) path, (uint64_t)(uintptr_t) buf, (uint64_t) len, NOTUSED, NOTUSED, NOTUSED);
}
weak_alias (__readlink, readlink)
weak_alias(__libc_readlink, readlink)
18 changes: 18 additions & 0 deletions src/glibc/sysdeps/unix/sysv/linux/readlinkat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <unistd.h>
#include <fcntl.h>
#include <sysdep-cancel.h>
#include <syscall-template.h>

/* Read the contents of the symbolic link PATH into no more than
LEN bytes of BUF. The contents are not null-terminated.
Returns the number of characters read, or -1 for errors. */
/*
* Edit Note:
* We implement both `readlink` and `readlinkat` in RawPOSIX, so changed the normal
*/
ssize_t
__libc_readlinkat (int fd, const char *path, char *buf, size_t len)
{
return MAKE_SYSCALL(166, "syscall|readlinkat",(uint64_t) fd, (uint64_t) path, (uint64_t)(uintptr_t) buf, (uint64_t) len, NOTUSED, NOTUSED);
}
weak_alias(__libc_readlinkat, readlinkat)