-
Notifications
You must be signed in to change notification settings - Fork 14
Direct shebang execution #116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |
| #include <fcntl.h> | ||
| #include <unistd.h> | ||
| #include <sys/stat.h> | ||
| #include <errno.h> | ||
|
|
||
| #include "core/elf.h" | ||
| #include "debug/log.h" | ||
|
|
@@ -427,3 +428,88 @@ void elf_resolve_interp(const char *sysroot, | |
| /* Strategy 3: use interp_path as-is */ | ||
| str_copy_trunc(out, interp_path, out_sz); | ||
| } | ||
|
|
||
| int elf_read_shebang(const char *host_path, | ||
| char *interp_out, | ||
| size_t interp_sz, | ||
| char *arg_out, | ||
| size_t arg_sz) | ||
| { | ||
| int fd = open(host_path, O_RDONLY); | ||
| if (fd < 0) | ||
| return -errno; | ||
|
|
||
| char buf[512]; | ||
| ssize_t nread = read(fd, buf, sizeof(buf) - 1); | ||
| close_keep_errno(fd); | ||
|
|
||
| if (nread < 0) { | ||
| return -errno; | ||
| } | ||
| if (nread < 2 || buf[0] != '#' || buf[1] != '!') { | ||
| return 0; /* Not a shebang script */ | ||
| } | ||
|
Comment on lines
+449
to
+451
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is confusing to have shebang detection in function
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is a fair point. The function is responsible for both detection (checking for the
|
||
| buf[nread] = '\0'; | ||
|
|
||
| /* Ignore script bytes after the first line (find \n or \r). If the shebang | ||
| * line is longer than our 511-byte buffer (no EOL found but buffer is | ||
| * full), reject it. | ||
| */ | ||
| char *eol = strpbrk(buf + 2, "\r\n"); | ||
| if (!eol) { | ||
| if (nread == (ssize_t) (sizeof(buf) - 1)) { | ||
| return -ENOEXEC; /* Shebang line too long */ | ||
| } | ||
| } else { | ||
| *eol = '\0'; | ||
| } | ||
|
|
||
| char *ptr = buf + 2; | ||
| while (*ptr == ' ' || *ptr == '\t') { | ||
| ptr++; | ||
| } | ||
|
|
||
| /* Strip trailing whitespace/newlines of the whole shebang line */ | ||
| size_t len = strlen(ptr); | ||
| while (len > 0 && (ptr[len - 1] == ' ' || ptr[len - 1] == '\t' || | ||
| ptr[len - 1] == '\r' || ptr[len - 1] == '\n')) { | ||
| ptr[--len] = '\0'; | ||
| } | ||
|
|
||
| if (len == 0) { | ||
| return -ENOEXEC; /* Empty shebang interpreter */ | ||
| } | ||
|
|
||
| /* Parse interpreter path and single optional argument */ | ||
| char *interp = ptr; | ||
| char *space = strpbrk(ptr, " \t"); | ||
| char *arg = NULL; | ||
| if (space) { | ||
| *space = '\0'; | ||
| arg = space + 1; | ||
| /* Strip leading space of the argument */ | ||
| while (*arg == ' ' || *arg == '\t') { | ||
| arg++; | ||
| } | ||
| /* Strip trailing space/newlines/tabs of the argument */ | ||
| size_t arg_len = strlen(arg); | ||
| while (arg_len > 0 && | ||
| (arg[arg_len - 1] == ' ' || arg[arg_len - 1] == '\t' || | ||
| arg[arg_len - 1] == '\r' || arg[arg_len - 1] == '\n')) { | ||
| arg[--arg_len] = '\0'; | ||
| } | ||
| if (strlen(arg) == 0) { | ||
| arg = NULL; | ||
| } | ||
| } | ||
|
|
||
| if (str_copy_trunc(interp_out, interp, interp_sz) >= interp_sz) { | ||
| return -ENOEXEC; /* Buffer too small */ | ||
| } | ||
|
|
||
| if (str_copy_trunc(arg_out, arg ? arg : "", arg_sz) >= arg_sz) { | ||
| return -ENOEXEC; /* Buffer too small */ | ||
| } | ||
|
|
||
| return 1; /* Successfully parsed shebang */ | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Low: reads 511 of 512 bytes then treats the first line as complete; an over-long interpreter path is silently truncated rather than rejected. str_copy_trunc's size check catches the common case. Consider rejecting an unterminated first line. (Still more generous than Linux BINPRM_BUF_SIZE=256.)