]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
path-util: teach find_executable_full how to look into the root directory
authorMaanya Goenka <t-magoenka@microsoft.com>
Wed, 4 Aug 2021 18:59:45 +0000 (11:59 -0700)
committerMaanya Goenka <t-magoenka@microsoft.com>
Tue, 10 Aug 2021 17:14:01 +0000 (10:14 -0700)
When the root parameter in find_executable_full is set, chase_symlinks prefixes this root
to every check of the path name to find the complete path of the execuatble in case the
path provided is not absolute. This is only done for the non NULL root because otherwise
the chase_symlinks function would alter the behavior of some of the callers which would
in turn alter the outputs in a way that is undesirable. The find_execuatble_full function is
invoked by the verify_executable function in analyze-verify.

src/analyze/analyze-verify.c
src/basic/path-util.c
src/basic/path-util.h
src/core/execute.c
src/test/test-path-util.c

index 4fcec2fcdce8c988037199ef01b0d7a7e172dcff..99bce68ca4f453b1a3f8c19a6f4a343eeb3a5607 100644 (file)
@@ -124,7 +124,7 @@ int verify_executable(Unit *u, const ExecCommand *exec) {
         if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE)
                 return 0;
 
-        r = find_executable_full(exec->path, false, NULL, NULL);
+        r = find_executable_full(exec->path, /* root= */ NULL, false, NULL, NULL);
         if (r < 0)
                 return log_unit_error_errno(u, r, "Command %s is not executable: %m", exec->path);
 
index 4aebb6541ea153c6832fd445881cffb225fca9e4..fe799da20b6ce73071f965fcf19a224f60d76ab2 100644 (file)
@@ -639,7 +639,7 @@ static int check_x_access(const char *path, int *ret_fd) {
         return 0;
 }
 
-int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd) {
+int find_executable_full(const char *name, const char *root, bool use_path_envvar, char **ret_filename, int *ret_fd) {
         int last_error, r;
         const char *p = NULL;
 
@@ -647,6 +647,25 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret_file
 
         if (is_path(name)) {
                 _cleanup_close_ int fd = -1;
+                _cleanup_free_ char *path_name = NULL;
+
+                /* Function chase_symlinks() is invoked only when root is not NULL,
+                 * as using it regardless of root value would alter the behavior
+                 * of existing callers for example: /bin/sleep would become
+                 * /usr/bin/sleep when find_executables is called. Hence, this function
+                 * should be invoked when needed to avoid unforeseen regression or other
+                 * complicated changes. */
+                if (root) {
+                        r = chase_symlinks(name,
+                                           root,
+                                           CHASE_PREFIX_ROOT,
+                                           &path_name,
+                                           /* ret_fd= */ NULL); /* prefix root to name in case full paths are not specified */
+                        if (r < 0)
+                                return r;
+
+                        name = path_name;
+                }
 
                 r = check_x_access(name, ret_fd ? &fd : NULL);
                 if (r < 0)
@@ -690,6 +709,23 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret_file
                 if (!path_extend(&element, name))
                         return -ENOMEM;
 
+                if (root) {
+                        char *path_name;
+
+                        r = chase_symlinks(element,
+                                           root,
+                                           CHASE_PREFIX_ROOT,
+                                           &path_name,
+                                           /* ret_fd= */ NULL);
+                        if (r < 0) {
+                                if (r != -EACCES)
+                                        last_error = r;
+                                continue;
+                        }
+
+                        free_and_replace(element, path_name);
+                }
+
                 r = check_x_access(element, ret_fd ? &fd : NULL);
                 if (r < 0) {
                         /* PATH entries which we don't have access to are ignored, as per tradition. */
index 26e7362d1f5865bb0aa5c596a524e40f7813bf33..0d69145497d50a51d6d44856355a629087e71a6e 100644 (file)
@@ -99,9 +99,9 @@ int path_strv_make_absolute_cwd(char **l);
 char** path_strv_resolve(char **l, const char *root);
 char** path_strv_resolve_uniq(char **l, const char *root);
 
-int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd);
+int find_executable_full(const char *name, const char *root, bool use_path_envvar, char **ret_filename, int *ret_fd);
 static inline int find_executable(const char *name, char **ret_filename) {
-        return find_executable_full(name, true, ret_filename, NULL);
+        return find_executable_full(name, /* root= */ NULL, true, ret_filename, NULL);
 }
 
 bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
index 460895625904ce98247d8456701cfa522c48f047..6635a35abf5661881700661d7822191fba567e36 100644 (file)
@@ -4351,7 +4351,7 @@ static int exec_child(
 
         _cleanup_free_ char *executable = NULL;
         _cleanup_close_ int executable_fd = -1;
-        r = find_executable_full(command->path, false, &executable, &executable_fd);
+        r = find_executable_full(command->path, /* root= */ NULL, false, &executable, &executable_fd);
         if (r < 0) {
                 if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
                         log_unit_struct_errno(unit, LOG_INFO, r,
index ceea7a62f5155b8cc3c4b3735f7bdce9bf9a584a..1a0fda5d1af90bae9ba32ef4d3d739c69d3c59b9 100644 (file)
@@ -204,12 +204,12 @@ static void test_find_executable_full(void) {
 
         log_info("/* %s */", __func__);
 
-        assert_se(find_executable_full("sh", true, &p, NULL) == 0);
+        assert_se(find_executable_full("sh", NULL, true, &p, NULL) == 0);
         puts(p);
         assert_se(streq(basename(p), "sh"));
         free(p);
 
-        assert_se(find_executable_full("sh", false, &p, NULL) == 0);
+        assert_se(find_executable_full("sh", NULL, false, &p, NULL) == 0);
         puts(p);
         assert_se(streq(basename(p), "sh"));
         free(p);
@@ -221,12 +221,12 @@ static void test_find_executable_full(void) {
 
         assert_se(unsetenv("PATH") == 0);
 
-        assert_se(find_executable_full("sh", true, &p, NULL) == 0);
+        assert_se(find_executable_full("sh", NULL, true, &p, NULL) == 0);
         puts(p);
         assert_se(streq(basename(p), "sh"));
         free(p);
 
-        assert_se(find_executable_full("sh", false, &p, NULL) == 0);
+        assert_se(find_executable_full("sh", NULL, false, &p, NULL) == 0);
         puts(p);
         assert_se(streq(basename(p), "sh"));
         free(p);
@@ -277,7 +277,7 @@ static void test_find_executable_exec_one(const char *path) {
         pid_t pid;
         int r;
 
-        r = find_executable_full(path, false, &t, &fd);
+        r = find_executable_full(path, NULL, false, &t, &fd);
 
         log_info_errno(r, "%s: %s → %s: %d/%m", __func__, path, t ?: "-", fd);