Skip to content

Commit e5da914

Browse files
committed
Allow fstat on standard pipes, re-arrange some system calls
1 parent 7246371 commit e5da914

File tree

2 files changed

+148
-145
lines changed

2 files changed

+148
-145
lines changed

lib/tinykvm/linux/system_calls.cpp

+142-142
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,10 @@ void Machine::setup_linux_system_calls()
155155
5, [] (vCPU& cpu) { // FSTAT
156156
auto& regs = cpu.registers();
157157

158-
int fd = cpu.machine().fds().translate(regs.rdi);
158+
int fd = regs.rdi;
159+
if (fd > 2) {
160+
fd = cpu.machine().fds().translate(regs.rdi);
161+
}
159162
struct stat vstat;
160163
regs.rax = fstat(fd, &vstat);
161164
if (regs.rax == 0) {
@@ -673,6 +676,19 @@ void Machine::setup_linux_system_calls()
673676
regs.rax);
674677
cpu.set_registers(regs);
675678
});
679+
Machine::install_syscall_handler(
680+
79, [](vCPU& cpu) { // GETCWD
681+
auto& regs = cpu.registers();
682+
683+
const char fakepath[] = "/";
684+
if (sizeof(fakepath) <= regs.rsi) {
685+
cpu.machine().copy_to_guest(regs.rdi, fakepath, sizeof(fakepath));
686+
regs.rax = regs.rdi;
687+
} else {
688+
regs.rax = 0;
689+
}
690+
cpu.set_registers(regs);
691+
});
676692
Machine::install_syscall_handler(
677693
89, [](vCPU& cpu) { // READLINK
678694
auto& regs = cpu.registers();
@@ -761,6 +777,22 @@ void Machine::setup_linux_system_calls()
761777
SYSPRINT("sched_getaffinity() = %lld\n", regs.rax);
762778
cpu.set_registers(regs);
763779
});
780+
Machine::install_syscall_handler(
781+
217, [](vCPU& cpu) { // GETDENTS64
782+
auto& regs = cpu.registers();
783+
784+
int fd = cpu.machine().fds().translate(regs.rdi);
785+
786+
char buffer[2048];
787+
regs.rax = syscall(SYS_getdents64, fd, buffer, sizeof(buffer));
788+
if (regs.rax > 0)
789+
{
790+
cpu.machine().copy_to_guest(regs.rsi, buffer, regs.rax);
791+
}
792+
SYSPRINT("GETDENTS64 to vfd=%lld, fd=%d, data=0x%llX = %lld\n",
793+
regs.rdi, fd, regs.rsi, regs.rax);
794+
cpu.set_registers(regs);
795+
});
764796
Machine::install_syscall_handler(
765797
228, [](vCPU& cpu) { // clock_gettime
766798
auto& regs = cpu.registers();
@@ -783,6 +815,104 @@ void Machine::setup_linux_system_calls()
783815
printf("Machine exits: _exit(%lld)\n", regs.rdi);
784816
#endif
785817
cpu.stop(); });
818+
Machine::install_syscall_handler(
819+
257, [] (vCPU& cpu) { // OPENAT
820+
auto& regs = cpu.registers();
821+
822+
const auto vpath = regs.rsi;
823+
const int flags = regs.rdx;
824+
825+
std::string path = cpu.machine().memcstring(vpath, PATH_MAX);
826+
bool write_flags = (flags & (O_WRONLY | O_RDWR)) != 0x0;
827+
if (!write_flags)
828+
{
829+
try {
830+
std::string real_path = path;
831+
if (!cpu.machine().fds().is_readable_path(real_path)) {
832+
throw std::runtime_error("Path not readable: " + real_path);
833+
}
834+
835+
int fd = openat(AT_FDCWD, real_path.c_str(), flags);
836+
if (fd > 0) {
837+
regs.rax = cpu.machine().fds().manage(fd, false);
838+
} else {
839+
regs.rax = -1;
840+
}
841+
SYSPRINT("OPENAT fd=%lld path=%s (real_path=%s) = %d (%lld)\n",
842+
regs.rdi, path.c_str(), real_path.c_str(), fd, regs.rax);
843+
cpu.set_registers(regs);
844+
return;
845+
} catch (...) {
846+
SYSPRINT("OPENAT fd=%lld path=%s flags=%X = %d\n",
847+
regs.rdi, path.c_str(), flags, -1);
848+
regs.rax = -1;
849+
}
850+
}
851+
if (write_flags || regs.rax == (__u64)-1)
852+
{
853+
try {
854+
std::string real_path = path;
855+
if (!cpu.machine().fds().is_writable_path(real_path)) {
856+
throw std::runtime_error("Path not writable: " + real_path);
857+
}
858+
859+
int fd = openat(AT_FDCWD, real_path.c_str(), flags, S_IWUSR | S_IRUSR);
860+
SYSPRINT("OPENAT where=%lld path=%s (real_path=%s) flags=%X = fd %d\n",
861+
regs.rdi, path.c_str(), real_path.c_str(), flags, fd);
862+
863+
if (fd > 0) {
864+
regs.rax = cpu.machine().fds().manage(fd, false);
865+
} else {
866+
regs.rax = -1;
867+
}
868+
} catch (...) {
869+
regs.rax = -1;
870+
}
871+
}
872+
cpu.set_registers(regs);
873+
});
874+
Machine::install_syscall_handler(
875+
262, [] (vCPU& cpu) { // NEWFSTATAT
876+
auto& regs = cpu.registers();
877+
const auto vpath = regs.rsi;
878+
const auto buffer = regs.rdx;
879+
const int flags = regs.r8;
880+
int fd = AT_FDCWD;
881+
std::string path;
882+
883+
try {
884+
path = cpu.machine().memcstring(vpath, PATH_MAX);
885+
886+
if (regs.rdi != AT_FDCWD) {
887+
// Use existing vfd
888+
fd = cpu.machine().fds().translate(regs.rdi);
889+
890+
struct stat64 vstat;
891+
// We don't use path here, as a security measure
892+
regs.rax = fstatat64(fd, "", &vstat, flags);
893+
if (regs.rax == 0) {
894+
cpu.machine().copy_to_guest(buffer, &vstat, sizeof(vstat));
895+
}
896+
} else {
897+
if (!cpu.machine().fds().is_readable_path(path)) {
898+
regs.rax = -EPERM;
899+
} else {
900+
struct stat64 vstat;
901+
// Path is in allow-list
902+
regs.rax = fstatat64(AT_FDCWD, path.c_str(), &vstat, flags);
903+
if (regs.rax == 0) {
904+
cpu.machine().copy_to_guest(buffer, &vstat, sizeof(vstat));
905+
}
906+
}
907+
}
908+
} catch (...) {
909+
regs.rax = -1;
910+
}
911+
912+
SYSPRINT("NEWFSTATAT to vfd=%lld, vfd=%d, path=%s, data=0x%llX, flags=0x%X = %lld\n",
913+
regs.rdi, fd, path.c_str(), buffer, flags, regs.rax);
914+
cpu.set_registers(regs);
915+
});
786916
Machine::install_syscall_handler(
787917
273, [](vCPU& cpu)
788918
{
@@ -887,147 +1017,6 @@ void Machine::setup_linux_system_calls()
8871017
g_buf, bytes, flags, regs.rax);
8881018
cpu.set_registers(regs);
8891019
});
890-
Machine::install_syscall_handler(
891-
334, [](vCPU& cpu) { // faccessat
892-
auto& regs = cpu.registers();
893-
regs.rax = -ENOSYS;
894-
SYSPRINT("faccessat(...) = %lld\n",
895-
regs.rax);
896-
cpu.set_registers(regs);
897-
});
898-
899-
// Threads: clone, futex, block/tkill etc.
900-
Machine::setup_multithreading();
901-
Machine::install_syscall_handler(
902-
79, [](vCPU& cpu) { // GETCWD
903-
auto& regs = cpu.registers();
904-
905-
const char fakepath[] = "/";
906-
if (sizeof(fakepath) <= regs.rsi) {
907-
cpu.machine().copy_to_guest(regs.rdi, fakepath, sizeof(fakepath));
908-
regs.rax = regs.rdi;
909-
} else {
910-
regs.rax = 0;
911-
}
912-
cpu.set_registers(regs);
913-
});
914-
Machine::install_syscall_handler(
915-
217, [](vCPU& cpu) { // GETDENTS64
916-
auto& regs = cpu.registers();
917-
918-
int fd = cpu.machine().fds().translate(regs.rdi);
919-
920-
char buffer[2048];
921-
regs.rax = syscall(SYS_getdents64, fd, buffer, sizeof(buffer));
922-
if (regs.rax > 0)
923-
{
924-
cpu.machine().copy_to_guest(regs.rsi, buffer, regs.rax);
925-
}
926-
SYSPRINT("GETDENTS64 to vfd=%lld, fd=%d, data=0x%llX = %lld\n",
927-
regs.rdi, fd, regs.rsi, regs.rax);
928-
cpu.set_registers(regs);
929-
});
930-
Machine::install_syscall_handler(
931-
257, [] (vCPU& cpu) { // OPENAT
932-
auto& regs = cpu.registers();
933-
934-
const auto vpath = regs.rsi;
935-
const int flags = regs.rdx;
936-
937-
std::string path = cpu.machine().memcstring(vpath, PATH_MAX);
938-
bool write_flags = (flags & (O_WRONLY | O_RDWR)) != 0x0;
939-
if (!write_flags)
940-
{
941-
try {
942-
std::string real_path = path;
943-
if (!cpu.machine().fds().is_readable_path(real_path)) {
944-
throw std::runtime_error("Path not readable: " + real_path);
945-
}
946-
947-
int fd = openat(AT_FDCWD, real_path.c_str(), flags);
948-
if (fd > 0) {
949-
regs.rax = cpu.machine().fds().manage(fd, false);
950-
} else {
951-
regs.rax = -1;
952-
}
953-
SYSPRINT("OPENAT fd=%lld path=%s (real_path=%s) = %d (%lld)\n",
954-
regs.rdi, path.c_str(), real_path.c_str(), fd, regs.rax);
955-
cpu.set_registers(regs);
956-
return;
957-
} catch (...) {
958-
SYSPRINT("OPENAT fd=%lld path=%s flags=%X = %d\n",
959-
regs.rdi, path.c_str(), flags, -1);
960-
regs.rax = -1;
961-
}
962-
}
963-
if (write_flags || regs.rax == (__u64)-1)
964-
{
965-
try {
966-
std::string real_path = path;
967-
if (!cpu.machine().fds().is_writable_path(real_path)) {
968-
throw std::runtime_error("Path not writable: " + real_path);
969-
}
970-
971-
int fd = openat(AT_FDCWD, real_path.c_str(), flags, S_IWUSR | S_IRUSR);
972-
SYSPRINT("OPENAT where=%lld path=%s (real_path=%s) flags=%X = fd %d\n",
973-
regs.rdi, path.c_str(), real_path.c_str(), flags, fd);
974-
975-
if (fd > 0) {
976-
regs.rax = cpu.machine().fds().manage(fd, false);
977-
} else {
978-
regs.rax = -1;
979-
}
980-
} catch (...) {
981-
regs.rax = -1;
982-
}
983-
}
984-
cpu.set_registers(regs);
985-
});
986-
Machine::install_syscall_handler(
987-
262, [] (vCPU& cpu) { // NEWFSTATAT
988-
auto& regs = cpu.registers();
989-
const auto vpath = regs.rsi;
990-
const auto buffer = regs.rdx;
991-
const int flags = regs.r8;
992-
long fd = AT_FDCWD;
993-
std::string path;
994-
995-
try {
996-
path = cpu.machine().memcstring(vpath, PATH_MAX);
997-
998-
if (regs.rdi != AT_FDCWD) {
999-
// Use existing vfd
1000-
fd = cpu.machine().fds().translate(regs.rdi);
1001-
1002-
struct stat64 vstat;
1003-
// We don't use path here, as a security measure
1004-
regs.rax = fstatat64(fd, "", &vstat, flags);
1005-
if (regs.rax == 0) {
1006-
cpu.machine().copy_to_guest(buffer, &vstat, sizeof(vstat));
1007-
}
1008-
} else {
1009-
if (!cpu.machine().fds().is_readable_path(path)) {
1010-
regs.rax = -EPERM;
1011-
} else {
1012-
// Translate from vfd when fd != CWD
1013-
if ((long)regs.rdi != fd) fd = cpu.machine().fds().translate(regs.rdi);
1014-
1015-
struct stat64 vstat;
1016-
// Path is sanitized, so we can use it
1017-
regs.rax = fstatat64(fd, path.c_str(), &vstat, flags);
1018-
if (regs.rax == 0) {
1019-
cpu.machine().copy_to_guest(buffer, &vstat, sizeof(vstat));
1020-
}
1021-
}
1022-
}
1023-
} catch (...) {
1024-
regs.rax = -1;
1025-
}
1026-
1027-
SYSPRINT("NEWFSTATAT to vfd=%lld, fd=%ld, path=%s, data=0x%llX, flags=0x%X = %lld\n",
1028-
regs.rdi, fd, path.c_str(), buffer, flags, regs.rax);
1029-
cpu.set_registers(regs);
1030-
});
10311020
Machine::install_syscall_handler(
10321021
332, [] (vCPU& cpu) { // STATX
10331022
auto& regs = cpu.registers();
@@ -1061,6 +1050,17 @@ void Machine::setup_linux_system_calls()
10611050
regs.rdi, fd, path.c_str(), buffer, flags, mask, regs.rax);
10621051
cpu.set_registers(regs);
10631052
});
1053+
Machine::install_syscall_handler(
1054+
334, [](vCPU& cpu) { // faccessat
1055+
auto& regs = cpu.registers();
1056+
regs.rax = -ENOSYS;
1057+
SYSPRINT("faccessat(...) = %lld\n",
1058+
regs.rax);
1059+
cpu.set_registers(regs);
1060+
});
1061+
1062+
// Threads: clone, futex, block/tkill etc.
1063+
Machine::setup_multithreading();
10641064
}
10651065

10661066
} // tinykvm

lib/tinykvm/linux/threads.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,12 @@ void Machine::setup_multithreading()
317317
if (cpu.machine().threads().suspend_and_yield()) {
318318
return;
319319
}
320-
// Avoid spin-waiting solution, let's just end execution for now :)
321-
regs.rax = -EINTR;
322-
throw std::runtime_error("DEADLOCK_REACHED");
320+
// Deadlock reached. XXX: Force-unlock to continue
321+
// execution.
322+
futexVal = 0;
323+
cpu.machine().copy_to_guest(addr, &futexVal, sizeof(futexVal));
324+
regs.rax = 0;
325+
//throw std::runtime_error("DEADLOCK_REACHED");
323326
} else {
324327
regs.rax = 0;
325328
}

0 commit comments

Comments
 (0)