Skip to content

Launcher fails with "execv failed: Permission denied (13)" #44

Description

@nirvdrum

I recently installed JRuby 9.3.1.0 using ruby-build. The ruby-build recipe will install the jruby-launcher gem, which will replace bin/jruby in the distribution. When I try to run JRuby, I see the following error:

execv failed: Permission denied (13)

If I fetch the JRuby tarball and run it locally with the original bin/jruby, everything works. I've narrowed the issue down to the replaced launcher from jruby-launcher. Moreover, I've discovered I only get the failure when the JAVA_HOME env var is not set. With other Java applications, that isn't an issue as java is available on the PATH.

Currently, my java command is coming from Homebrew for Linux:

> which java
/home/linuxbrew/.linuxbrew/bin/java

> ls -l (which java)
lrwxrwxrwx 1 nirvdrum nirvdrum 29 Sep 22 14:59 /home/linuxbrew/.linuxbrew/bin/java -> ../Cellar/openjdk/17/bin/java*

> readlink -f (which java)
/home/linuxbrew/.linuxbrew/Cellar/openjdk/17/libexec/bin/java

If I set my JAVA_HOME env var to /home/linuxbrew/.linuxbrew/Cellar/openjdk/17 the launcher begins working.

Here is the strace output when trying to start the launcher:

> strace ./jruby -v
execve("./jruby", ["./jruby", "-v"], 0x7ffed4255d18 /* 79 vars */) = 0
brk(NULL)                               = 0x560ea10cd000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe50c88c00) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=109534, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 109534, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f45ae8b1000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\22\n\0\0\0\0\0"..., 832) = 832
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2182368, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f45ae8af000
mmap(NULL, 2197632, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f45ae696000
mmap(0x7f45ae72f000, 1060864, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x99000) = 0x7f45ae72f000
mmap(0x7f45ae832000, 442368, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19c000) = 0x7f45ae832000
mmap(0x7f45ae89e000, 57344, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x207000) = 0x7f45ae89e000
mmap(0x7f45ae8ac000, 10368, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f45ae8ac000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3405\0\0\0\0\0\0"..., 832) = 832
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=104984, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 107592, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f45ae67b000
mprotect(0x7f45ae67e000, 90112, PROT_NONE) = 0
mmap(0x7f45ae67e000, 73728, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f45ae67e000
mmap(0x7f45ae690000, 12288, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15000) = 0x7f45ae690000
mmap(0x7f45ae694000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18000) = 0x7f45ae694000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\206\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0+H)\227\201T\214\233\304R\352\306\3379\220%"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=1983576, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2012056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f45ae48f000
mmap(0x7f45ae4b5000, 1486848, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000) = 0x7f45ae4b5000
mmap(0x7f45ae620000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x191000) = 0x7f45ae620000
mmap(0x7f45ae66c000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1dc000) = 0x7f45ae66c000
mmap(0x7f45ae672000, 33688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f45ae672000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\363\0\0\0\0\0\0"..., 832) = 832
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=1364824, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 1364240, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f45ae341000
mmap(0x7f45ae350000, 679936, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xf000) = 0x7f45ae350000
mmap(0x7f45ae3f6000, 618496, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xb5000) = 0x7f45ae3f6000
mmap(0x7f45ae48d000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14b000) = 0x7f45ae48d000
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f45ae33f000
arch_prctl(ARCH_SET_FS, 0x7f45ae340180) = 0
mprotect(0x7f45ae66c000, 12288, PROT_READ) = 0
mprotect(0x7f45ae48d000, 4096, PROT_READ) = 0
mprotect(0x7f45ae694000, 4096, PROT_READ) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f45ae33d000
mprotect(0x7f45ae89e000, 45056, PROT_READ) = 0
mprotect(0x560e9fe23000, 4096, PROT_READ) = 0
mprotect(0x7f45ae8fe000, 8192, PROT_READ) = 0
munmap(0x7f45ae8b1000, 109534)          = 0
brk(NULL)                               = 0x560ea10cd000
brk(0x560ea10ee000)                     = 0x560ea10ee000
readlink("/proc/self/exe", "/tmp/jruby/jruby-9.3.1.0/bin/jru"..., 4096) = 34
newfstatat(AT_FDCWD, "/tmp/jruby/jruby-9.3.1.0/bin/jruby", {st_mode=S_IFREG|0755, st_size=97176, ...}, 0) = 0
access("/dev/urandom", R_OK)            = 0
newfstatat(AT_FDCWD, "/home/nirvdrum/.rbenv/shims/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/opt/JetBrains/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/.rbenv/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/.cargo/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/dev/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/opt/wine-staging/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/.local/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/.opam/4.11.1/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/.cargo/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/.local/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/nirvdrum/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/local/sbin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/local/bin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/sbin/java", 0x7ffe50c877a0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/bin/java", {st_mode=S_IFDIR|0755, st_size=11, ...}, 0) = 0
access("/usr/libexec/java_home", R_OK|X_OK) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/bin/java", {st_mode=S_IFLNK|0777, st_size=22, ...}, AT_SYMLINK_NOFOLLOW) = 0
readlink("/usr", 0x7ffe50c85f40, 1023)  = -1 EINVAL (Invalid argument)
readlink("/usr/bin", 0x7ffe50c85f40, 1023) = -1 EINVAL (Invalid argument)
readlink("/usr/bin/java", "/etc/alternatives/java", 1023) = 22
readlink("/etc", 0x7ffe50c85f40, 1023)  = -1 EINVAL (Invalid argument)
readlink("/etc/alternatives", 0x7ffe50c85f40, 1023) = -1 EINVAL (Invalid argument)
readlink("/etc/alternatives/java", "/usr/lib/jvm/java-1.15.0-openjdk"..., 1023) = 38
readlink("/usr", 0x7ffe50c85f40, 1023)  = -1 EINVAL (Invalid argument)
readlink("/usr/lib", 0x7ffe50c85f40, 1023) = -1 EINVAL (Invalid argument)
readlink("/usr/lib/jvm", 0x7ffe50c85f40, 1023) = -1 EINVAL (Invalid argument)
readlink("/usr/lib/jvm/java-1.15.0-openjdk-amd64", "java-15-openjdk-amd64", 1023) = 21
readlink("/usr/lib/jvm/java-15-openjdk-amd64", 0x7ffe50c85f40, 1023) = -1 EINVAL (Invalid argument)
newfstatat(AT_FDCWD, "/tmp/jruby/jruby-9.3.1.0/lib/jni", {st_mode=S_IFDIR|0775, st_size=440, ...}, 0) = 0
uname({sysname="Linux", nodename="melchior-linux", ...}) = 0
openat(AT_FDCWD, "/tmp/jruby/jruby-9.3.1.0/lib/jni", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0775, st_size=440, ...}, AT_EMPTY_PATH) = 0
getdents64(3, 0x560ea10df4e0 /* 22 entries */, 32768) = 768
getdents64(3, 0x560ea10df4e0 /* 0 entries */, 32768) = 0
close(3)                                = 0
access("/usr/lib/lib/modules", R_OK)    = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/release", O_RDONLY) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/tmp/jruby/jruby-9.3.1.0/lib/jruby.jar", {st_mode=S_IFREG|0644, st_size=15651642, ...}, 0) = 0
newfstatat(AT_FDCWD, "/tmp/jruby/jruby-9.3.1.0/lib/jruby.jar", {st_mode=S_IFREG|0644, st_size=15651642, ...}, 0) = 0
newfstatat(AT_FDCWD, "/tmp/jruby/jruby-9.3.1.0/lib/jruby-complete.jar", 0x7ffe50c87280, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/tmp/jruby/jruby-9.3.1.0/lib", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=100, ...}, AT_EMPTY_PATH) = 0
brk(0x560ea1110000)                     = 0x560ea1110000
getdents64(3, 0x560ea10e7990 /* 5 entries */, 32768) = 128
getdents64(3, 0x560ea10e7990 /* 0 entries */, 32768) = 0
brk(0x560ea1108000)                     = 0x560ea1108000
close(3)                                = 0
newfstatat(AT_FDCWD, "/usr/lib/jvm/java-15-openjdk-amd64", {st_mode=S_IFDIR|0755, st_size=11, ...}, 0) = 0
execve("/usr/lib/jvm/java-15-openjdk-amd64", ["/usr/lib/jvm/java-15-openjdk-amd"..., "-Djdk.home=/usr/lib", "-Djruby.home=/tmp/jruby/jruby-9."..., "-Djruby.script=jruby", "-Djruby.shell=/bin/sh", "-Djffi.boot.library.path=/tmp/jr"..., "-Xss2048k", "-Dsun.java.command=org.jruby.Mai"..., "-Xbootclasspath/a:/tmp/jruby/jru"..., "-cp", "", "-Djava.security.egd=file:/dev/ur"..., "org/jruby/Main", "-v"], 0x7ffe50c88d70 /* 79 vars */) = -1 EACCES (Permission denied)
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0xa), ...}, AT_EMPTY_PATH) = 0
write(1, "execv failed: Permission denied "..., 37execv failed: Permission denied (13)
) = 37
exit_group(255)                         = ?
+++ exited with 255 +++

This looks like a similar situation to #31.

Activity

  1. nirvdrum commented on Nov 23, 2021

    @nirvdrum
    Author

    Debugging this with @headius, it looks like there are two errors. First, my /usr/bin/java, through a chain of symlinks, points at a JVM directory rather than the binary. This appears to be a misuse of Ubuntu's update-alternatives command. I hadn't caught it because java gets picked up in a later PATH entry when working in my shell. The second issue is the launcher, while iterating through PATH entries, finds the bad /usr/bin/java value and assumes it's an executable file and stops searching at that point. Thus, the resolution logic ends up being different from the shell.

    I'll fix this on my machine, but it's probably worth making the launcher a bit more resilient. If nothing else, it could present the user with a neater error message.

  2. headius commented on Dec 7, 2021

    @headius
    Member

    The simple fix will be to check that the java command we find in PATH actually resolves to an executable file rather than a directory. I believe that will resolve this for @nirvdrum and any future users with peculiar java dirs in their PATH.

  3. andrykonchin commented on Feb 20, 2025

    @andrykonchin

    Have a similar issue after installing JRuby with rbenv. I accidentally neither have JAVA_HOME env var set nor java on the PATH. So the execv failed: Permission denied (13) error message was confusing to me.

    It will be great to have the error message more specific and friendly to point at the issue.

  4. headius commented on Feb 20, 2025

    @headius
    Member

    @mrnoname1000 Maybe we can make the java locating more robust, with a reasonable error when all options fail to find an executable?

  5. headius commented on Feb 21, 2025

    @headius
    Member

    Just occurred to me that this is an issue with the native version of jruby-launcher, not the shell script. We have an improvement for the latter from @mrnoname1000 in jruby/jruby#8648 but the native launcher will need a similar fix (plus a ton of updates for recent shell launcher updates).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions