@@ -1409,7 +1409,10 @@ void Machine::setup_linux_system_calls()
14091409 if (bufsiz > buf.size ()) {
14101410 regs.rax = -EINVAL;
14111411 } else if (!cpu.machine ().fds ().is_readable_path (path)) {
1412- regs.rax = -EACCES;
1412+ // This should be a permission error or EACCES, but some run-times
1413+ // like to recurse from root up to the path, which we don't want to
1414+ // allow. So instead we return EINVAL to pretend the path is not a link.
1415+ regs.rax = -EINVAL;
14131416 } else {
14141417 // Read the link
14151418 ssize_t result = readlink (path.c_str (), buf.data (), bufsiz);
@@ -1782,12 +1785,23 @@ void Machine::setup_linux_system_calls()
17821785 }
17831786
17841787 if (!cpu.machine ().fds ().is_readable_path (path) && !path.empty ()) {
1785- regs.rax = -EPERM;
1788+ // Path is not readable, however, if this is a "readlink" attempt,
1789+ // we should pretend the path is not a link instead.
1790+ if (regs.r10 & AT_SYMLINK_NOFOLLOW) {
1791+ // Create a fictional stat structure, pretending it's a directory
1792+ struct stat64 vstat {};
1793+ vstat.st_mode = S_IFDIR | 0644 ;
1794+ vstat.st_blksize = 512 ;
1795+ cpu.machine ().copy_to_guest (buffer, &vstat, sizeof (vstat));
1796+ regs.rax = 0 ;
1797+ } else {
1798+ regs.rax = -EPERM;
1799+ }
17861800 } else {
17871801 // If path is empty, use AT_EMPTY_PATH to operate on the fd
17881802 flags = (path.empty () && vfd != AT_FDCWD) ? AT_EMPTY_PATH : 0 ;
17891803
1790- struct stat64 vstat;
1804+ struct stat64 vstat {} ;
17911805 // Path is in allow-list
17921806 const int result = fstatat64 (fd, path.c_str (), &vstat, flags);
17931807 if (result == 0 ) {
@@ -2134,7 +2148,8 @@ void Machine::setup_linux_system_calls()
21342148 try {
21352149 path = cpu.machine ().memcstring (vpath, PATH_MAX);
21362150 if (!cpu.machine ().fds ().is_readable_path (path)) {
2137- regs.rax = -EPERM;
2151+ // Pretend the path is not a link
2152+ regs.rax = -EINVAL;
21382153 } else {
21392154 int fd = cpu.machine ().fds ().current_working_directory_fd ();
21402155 // Translate from vfd when fd != AT_FDCWD
0 commit comments