From: Michael Tremer Date: Thu, 25 May 2023 13:32:30 +0000 (+0000) Subject: file: Replace /usr/bin/env with the absolute path if possible X-Git-Tag: 0.9.29~153 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=33d2d4df4411018bb293188155debf48e88006ca;p=people%2Fms%2Fpakfire.git file: Replace /usr/bin/env with the absolute path if possible Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/file.c b/src/libpakfire/file.c index 663c2e38f..f308ea02c 100644 --- a/src/libpakfire/file.c +++ b/src/libpakfire/file.c @@ -1253,7 +1253,7 @@ static int pakfire_file_levels(struct pakfire_file* file) { } FILE* pakfire_file_open(struct pakfire_file* file) { - FILE* f = fopen(file->abspath, "r"); + FILE* f = fopen(file->abspath, "r+"); if (!f) ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath); @@ -2519,6 +2519,133 @@ ERROR: return r; } +static int pakfire_file_fix_interpreter(struct pakfire_file* file, const char* interpreter) { + FILE* f = NULL; + char path[PATH_MAX]; + int r; + + char* data = NULL; + size_t length = 0; + + DEBUG(file->pakfire, "%s: Fixing interpreter %s\n", file->path, interpreter); + + // Open the file + f = pakfire_file_open(file); + if (!f) { + ERROR(file->pakfire, "Could not open %s: %m\n", file->path); + r = 1; + goto ERROR; + } + + // Read the entire content into the buffer + r = pakfire_read_file_into_buffer(f, &data, &length); + if (r) { + ERROR(file->pakfire, "Could not read file into memory: %m\n"); + goto ERROR; + } + + // Find the end of the first line + char* eol = memchr(data, '\n', length); + if (!eol) { + DEBUG(file->pakfire, "Could not find the end of the first line\n"); + errno = EINVAL; + r = 0; + goto ERROR; + } + + // Terminate the first line + *eol = '\0'; + + // Pointer to the beginning of the first line + char* p = data; + + // Pointer to the beginning of the rest of the script + const char* rest = eol + 1; + + DEBUG(file->pakfire, "First line: %s\n", p); + + // Read shebang + if (pakfire_string_startswith(p, "#!")) { + p += 2; + } else { + ERROR(file->pakfire, "%s: Could not find shebang\n", file->path); + errno = EINVAL; + r = 1; + goto ERROR; + } + + // Consume any whitespace + while (isspace(*p)) + p++; + + // Consume the old interpreter + while (!isspace(*p)) + p++; + + // Consume any whitespace + while (isspace(*p)) + p++; + + // The command begins here + const char* command = p; + + // Find the end of the command + while (!isspace(*p)) + p++; + + // Terminate the command + *p++ = '\0'; + + DEBUG(file->pakfire, "%s: Found command: %s\n", file->path, command); + + // Find the absolute path to the command + r = pakfire_which(file->pakfire, path, command); + if (r) { + DEBUG(file->pakfire, "%s: Could not resolve command %s: %m\n", file->path, command); + goto ERROR; + } + + // If we could not resolve the command, this file has an invalid interpreter + if (!*path) { + file->issues |= PAKFIRE_FILE_INVALID_INTERPRETER; + r = 0; + goto ERROR; + } + + // Go back to the beginning of the file + rewind(f); + + // Write shebang + r = fprintf(f, (*p) ? "#!%s %s\n" : "#!%s\n", path, p); + if (r < 0) { + ERROR(file->pakfire, "%s: Could not write back first line: %m\n", file->path); + r = 1; + goto ERROR; + } + + // Determine the length of the payload + length -= rest - data; + + // Write the rest + size_t bytes_written = fwrite(rest, 1, length, f); + if (bytes_written < length) { + ERROR(file->pakfire, "%s: Could not write the payload: %m\n", file->path); + r = 1; + goto ERROR; + } + + // Success! + r = 0; + +ERROR: + if (data) + free(data); + if (f) + fclose(f); + + return r; +} + static int pakfire_file_check_interpreter(struct pakfire_file* file) { char* interpreter = NULL; int r; @@ -2542,15 +2669,20 @@ static int pakfire_file_check_interpreter(struct pakfire_file* file) { else if (pakfire_string_startswith(interpreter, "/usr/local/")) file->issues |= PAKFIRE_FILE_INVALID_INTERPRETER; - // We don't support "env" - else if (strcmp(interpreter, "/usr/bin/env") == 0) - file->issues |= PAKFIRE_FILE_INVALID_INTERPRETER; + // We don't support "env", but will automatically fix it + else if (strcmp(interpreter, "/usr/bin/env") == 0) { + r = pakfire_file_fix_interpreter(file, interpreter); + if (r) { + ERROR(file->pakfire, "%s: Could not fix interpreter: %m\n", file->path); + goto ERROR; + } + } - // Cleanup +ERROR: if (interpreter) free(interpreter); - return 0; + return r; } static int pakfire_file_check_capabilities(struct pakfire_file* file) { diff --git a/src/libpakfire/include/pakfire/util.h b/src/libpakfire/include/pakfire/util.h index af56678e3..d9a1505d5 100644 --- a/src/libpakfire/include/pakfire/util.h +++ b/src/libpakfire/include/pakfire/util.h @@ -84,6 +84,10 @@ FILE* pakfire_mktemp(char* path, const mode_t mode); char* pakfire_mkdtemp(char* path); int pakfire_rmtree(const char* path, int flags); +#define pakfire_which(pakfire, path, what) \ + __pakfire_which(pakfire, path, sizeof(path), what) +int __pakfire_which(struct pakfire* pakfire, char* path, const size_t length, const char* what); + char* pakfire_generate_uuid(void); int pakfire_tty_is_noninteractive(void); diff --git a/src/libpakfire/util.c b/src/libpakfire/util.c index 12a8666e3..79cd196b1 100644 --- a/src/libpakfire/util.c +++ b/src/libpakfire/util.c @@ -660,6 +660,46 @@ int pakfire_rmtree(const char* path, int flags) { return r; } +int __pakfire_which(struct pakfire* pakfire, char* path, const size_t length, + const char* what) { + char buffer[PATH_MAX]; + int r; + + // Check input + if (!what) { + errno = EINVAL; + return 1; + } + + static const char* paths[] = { + "/usr/sbin", + "/sbin", + "/usr/bin", + "/bin", + NULL, + }; + + // Clear path + *path = '\0'; + + for (const char** p = paths; *p; p++) { + // Compose path + r = pakfire_path(pakfire, buffer, "%s/%s", *p, what); + if (r) + return r; + + // If the path exists and is executable we are done + if (access(buffer, X_OK) == 0) { + const char* relpath = pakfire_relpath(pakfire, buffer); + + // Store the result in path + return __pakfire_string_set(path, length, relpath); + } + } + + return 0; +} + // Archive Stuff int pakfire_archive_copy_data_from_file(struct pakfire* pakfire,