Skip to content

Commit 6272a23

Browse files
committed
Implement dup(), fcntl(F_GETFD) and allow more fd=0,1,2
1 parent 89b8750 commit 6272a23

File tree

2 files changed

+72
-29
lines changed

2 files changed

+72
-29
lines changed

lib/tinykvm/linux/fds.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,25 @@ namespace tinykvm
118118
return true;
119119
}
120120
auto it = m_allowed_readable_paths->find(modifiable_path);
121-
return (it != m_allowed_readable_paths->end());
121+
if (it != m_allowed_readable_paths->end())
122+
{
123+
return true;
124+
}
125+
// Iterate over the allowed paths and check if a path
126+
// starts with modifiable_path, however path cannot contain
127+
// any parent-directory components (..)
128+
if (modifiable_path.find("..") != std::string::npos)
129+
{
130+
return false;
131+
}
132+
for (const auto& path : *m_allowed_readable_paths)
133+
{
134+
if (modifiable_path.find(path) == 0)
135+
{
136+
return true;
137+
}
138+
}
139+
return false;
122140
}
123141

124142
bool FileDescriptors::is_writable_path(std::string& modifiable_path) const noexcept

lib/tinykvm/linux/system_calls.cpp

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,10 @@ void Machine::setup_linux_system_calls()
166166
Machine::install_syscall_handler(
167167
SYS_lseek, [] (vCPU& cpu) { // LSEEK
168168
auto& regs = cpu.registers();
169-
const int fd = cpu.machine().fds().translate(regs.rdi);
169+
int fd = regs.rdi;
170+
if (fd > 2) {
171+
fd = cpu.machine().fds().translate(regs.rdi);
172+
}
170173
regs.rax = lseek(fd, regs.rsi, regs.rdx);
171174
cpu.set_registers(regs);
172175
});
@@ -611,6 +614,27 @@ void Machine::setup_linux_system_calls()
611614
}
612615
cpu.set_registers(regs);
613616
});
617+
Machine::install_syscall_handler(
618+
SYS_dup, [](vCPU& cpu) { // DUP
619+
auto& regs = cpu.registers();
620+
int fd = regs.rdi;
621+
if (fd > 2)
622+
{
623+
fd = cpu.machine().fds().translate(fd);
624+
}
625+
const int new_fd = dup(fd);
626+
if (new_fd < 0)
627+
{
628+
regs.rax = -errno;
629+
}
630+
else
631+
{
632+
regs.rax = cpu.machine().fds().manage(new_fd, false, false);
633+
}
634+
SYSPRINT("dup(vfd=%lld fd=%d) = %lld\n",
635+
regs.rdi, fd, regs.rax);
636+
cpu.set_registers(regs);
637+
});
614638
Machine::install_syscall_handler(
615639
SYS_nanosleep, [](vCPU& cpu) { // nanosleep
616640
auto& regs = cpu.registers();
@@ -665,7 +689,14 @@ void Machine::setup_linux_system_calls()
665689
Machine::install_syscall_handler(
666690
SYS_fcntl, [](vCPU& cpu) { // FCNTL
667691
auto& regs = cpu.registers();
692+
const int fd = cpu.machine().fds().translate(regs.rdi);
693+
const int cmd = regs.rsi;
668694
regs.rax = 0;
695+
if (cmd == F_GETFD)
696+
{
697+
//const int flags = fcntl(fd, cmd);
698+
regs.rax = 0x1;
699+
}
669700
SYSPRINT("fcntl(...) = %lld\n",
670701
regs.rax);
671702
cpu.set_registers(regs);
@@ -871,40 +902,38 @@ void Machine::setup_linux_system_calls()
871902
auto& regs = cpu.registers();
872903
const auto vpath = regs.rsi;
873904
const auto buffer = regs.rdx;
874-
const int flags = regs.r8;
905+
const int flags = 0; // regs.r10;
875906
int fd = AT_FDCWD;
876907
std::string path;
877908

878909
try {
879910
path = cpu.machine().memcstring(vpath, PATH_MAX);
880911

881-
if (regs.rdi != AT_FDCWD) {
912+
if (int(regs.rdi) >= 0) {
882913
// Use existing vfd
883-
fd = cpu.machine().fds().translate(regs.rdi);
914+
fd = cpu.machine().fds().translate(int(regs.rdi));
915+
} else {
916+
// Use AT_FDCWD
917+
fd = AT_FDCWD;
918+
}
884919

920+
if (!cpu.machine().fds().is_readable_path(path)) {
921+
regs.rax = -EPERM;
922+
} else {
885923
struct stat64 vstat;
886-
// We don't use path here, as a security measure
887-
regs.rax = fstatat64(fd, "", &vstat, flags);
924+
// Path is in allow-list
925+
regs.rax = fstatat64(fd, path.c_str(), &vstat, flags);
888926
if (regs.rax == 0) {
889927
cpu.machine().copy_to_guest(buffer, &vstat, sizeof(vstat));
890-
}
891-
} else {
892-
if (!cpu.machine().fds().is_readable_path(path)) {
893-
regs.rax = -EPERM;
894928
} else {
895-
struct stat64 vstat;
896-
// Path is in allow-list
897-
regs.rax = fstatat64(AT_FDCWD, path.c_str(), &vstat, flags);
898-
if (regs.rax == 0) {
899-
cpu.machine().copy_to_guest(buffer, &vstat, sizeof(vstat));
900-
}
929+
regs.rax = -errno;
901930
}
902931
}
903932
} catch (...) {
904933
regs.rax = -1;
905934
}
906935

907-
SYSPRINT("NEWFSTATAT to vfd=%lld, vfd=%d, path=%s, data=0x%llX, flags=0x%X = %lld\n",
936+
SYSPRINT("NEWFSTATAT to vfd=%lld, fd=%d, path=%s, data=0x%llX, flags=0x%X = %lld\n",
908937
regs.rdi, fd, path.c_str(), buffer, flags, regs.rax);
909938
cpu.set_registers(regs);
910939
});
@@ -1048,26 +1077,22 @@ void Machine::setup_linux_system_calls()
10481077
Machine::install_syscall_handler(
10491078
SYS_readlinkat, [](vCPU& cpu) { // READLINKAT
10501079
auto& regs = cpu.registers();
1080+
const int vfd = regs.rdi;
10511081
const auto vpath = regs.rsi;
10521082
const auto g_buffer = regs.rdx;
10531083
const int flags = regs.r8;
1054-
int fd = AT_FDCWD;
10551084
std::string path;
10561085
try {
10571086
path = cpu.machine().memcstring(vpath, PATH_MAX);
10581087
if (!cpu.machine().fds().is_readable_path(path)) {
1059-
fd = cpu.machine().fds().translate(regs.rdi);
1060-
1061-
char buffer[PATH_MAX];
1062-
regs.rax = readlinkat(fd, "", buffer, sizeof(buffer));
1063-
if (regs.rax > 0) {
1064-
cpu.machine().copy_to_guest(g_buffer, buffer, regs.rax);
1065-
} else {
1066-
regs.rax = -errno;
1067-
}
1088+
regs.rax = -EPERM;
10681089
} else {
1090+
int fd = vfd;
1091+
// Translate from vfd when fd != AT_FDCWD
1092+
if (vfd != AT_FDCWD)
1093+
fd = cpu.machine().fds().translate(vfd);
10691094
// Path is in allow-list
1070-
regs.rax = readlinkat(AT_FDCWD, path.c_str(), (char *)g_buffer, regs.rdx);
1095+
regs.rax = readlinkat(fd, path.c_str(), (char *)g_buffer, regs.rdx);
10711096
if (regs.rax > 0) {
10721097
cpu.machine().copy_to_guest(g_buffer, path.c_str(), regs.rax);
10731098
} else {

0 commit comments

Comments
 (0)