Skip to content
Merged
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
1 change: 1 addition & 0 deletions kernel/arch/aarch64/syscall/linux_syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ constexpr uint64_t WRITE = 64;
constexpr uint64_t WRITEV = 66;
constexpr uint64_t PSELECT6 = 72;
constexpr uint64_t PPOLL = 73;
constexpr uint64_t READLINKAT = 78;
constexpr uint64_t NEWFSTATAT = 79;
constexpr uint64_t FSTAT = 80;
constexpr uint64_t FSYNC = 82;
Expand Down
2 changes: 2 additions & 0 deletions kernel/arch/x86_64/syscall/linux_syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ constexpr uint64_t RENAME = 82;
constexpr uint64_t MKDIR = 83;
constexpr uint64_t RMDIR = 84;
constexpr uint64_t UNLINK = 87;
constexpr uint64_t READLINK = 89;
constexpr uint64_t GETTIMEOFDAY = 96;
constexpr uint64_t GETUID = 102;
constexpr uint64_t GETGID = 104;
Expand All @@ -70,6 +71,7 @@ constexpr uint64_t MKDIRAT = 258;
constexpr uint64_t NEWFSTATAT = 262;
constexpr uint64_t UNLINKAT = 263;
constexpr uint64_t RENAMEAT = 264;
constexpr uint64_t READLINKAT = 267;
constexpr uint64_t FACCESSAT = 269;
constexpr uint64_t PSELECT6 = 270;
constexpr uint64_t PPOLL = 271;
Expand Down
67 changes: 67 additions & 0 deletions kernel/syscall/handlers/sys_fd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,73 @@ DEFINE_SYSCALL2(access, pathname, mode) {
pathname, mode, 0, 0, 0);
}

static int64_t do_readlinkat(int64_t dirfd, uint64_t pathname,
uint64_t u_buf, uint64_t bufsize) {
if (bufsize == 0) {
return syscall::EINVAL;
}

char kpath[fs::PATH_MAX];
int32_t copy_rc = mm::uaccess::copy_cstr_from_user(
kpath, sizeof(kpath),
reinterpret_cast<const char*>(pathname));
if (copy_rc != mm::uaccess::OK) {
if (copy_rc == mm::uaccess::ERR_NAMETOOLONG) {
return syscall::ENAMETOOLONG;
}
return syscall::EFAULT;
}

if (kpath[0] == '\0') {
return syscall::ENOENT;
}

sched::task* task = sched::current();
if (!task) {
return syscall::EIO;
}

fs::node* node = nullptr;
int64_t lookup_rc = lookup_node_for_dirfd_path(task, dirfd, kpath, &node);
if (lookup_rc != 0) {
return lookup_rc;
}

// Only symbolic links have a target to read
if (node->type() != fs::node_type::symlink) {
release_node_ref(node);
return syscall::EINVAL;
}

// The input path is no longer needed, so reuse kpath for the target
size_t cap = bufsize < sizeof(kpath) ? bufsize : sizeof(kpath);
size_t target_len = 0;
int32_t fs_rc = node->readlink(kpath, cap, &target_len);
release_node_ref(node);
if (fs_rc != fs::OK) {
return syscall::error_map::map_fs_error(fs_rc);
}

// Guard against a provider reporting more than it wrote
if (target_len > cap) {
target_len = cap;
}

if (mm::uaccess::copy_to_user(reinterpret_cast<void*>(u_buf),
kpath, target_len) != mm::uaccess::OK) {
return syscall::EFAULT;
}
return static_cast<int64_t>(target_len);
}

DEFINE_SYSCALL4(readlinkat, dirfd, pathname, buf, bufsize) {
return do_readlinkat(static_cast<int64_t>(dirfd), pathname, buf, bufsize);
}

DEFINE_SYSCALL3(readlink, pathname, buf, bufsize) {
return do_readlinkat(static_cast<int64_t>(-100), pathname, buf, bufsize);
}

DEFINE_SYSCALL4(renameat, olddirfd, oldpath, newdirfd, newpath) {
(void)olddirfd;
(void)oldpath;
Expand Down
2 changes: 2 additions & 0 deletions kernel/syscall/handlers/sys_fd.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ DECLARE_SYSCALL(mkdirat);
DECLARE_SYSCALL(mkdir);
DECLARE_SYSCALL(faccessat);
DECLARE_SYSCALL(access);
DECLARE_SYSCALL(readlinkat);
DECLARE_SYSCALL(readlink);
DECLARE_SYSCALL(renameat);
DECLARE_SYSCALL(fsync);

Expand Down
3 changes: 3 additions & 0 deletions kernel/syscall/handlers/sys_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,8 @@ DEFINE_SYSCALL3(ioctl, fd, cmd, arg) {
task, static_cast<resource::handle_t>(fd),
static_cast<uint32_t>(cmd), arg);
if (rc == resource::OK) return 0;

// POSIX: an unsupported request on any fd is ENOTTY, not ENOSYS
if (rc == resource::ERR_UNSUP) return syscall::ENOTTY;
return map_resource_error(rc);
}
2 changes: 2 additions & 0 deletions kernel/syscall/syscall_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,14 @@ __PRIVILEGED_CODE void init_syscall_table() {
REGISTER_SYSCALL(linux_nr::UNLINKAT, unlinkat);
REGISTER_SYSCALL(linux_nr::FACCESSAT, faccessat);
REGISTER_SYSCALL(linux_nr::RENAMEAT, renameat);
REGISTER_SYSCALL(linux_nr::READLINKAT, readlinkat);
#if defined(__x86_64__)
REGISTER_SYSCALL(linux_nr::MKDIR, mkdir);
REGISTER_SYSCALL(linux_nr::UNLINK, unlink);
REGISTER_SYSCALL(linux_nr::RMDIR, rmdir);
REGISTER_SYSCALL(linux_nr::ACCESS, access);
REGISTER_SYSCALL(linux_nr::RENAME, renameat);
REGISTER_SYSCALL(linux_nr::READLINK, readlink);
#endif

REGISTER_SYSCALL(SYS_ELEVATE, elevate);
Expand Down
Loading