]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf script: Use openat for directory iteration
authorIan Rogers <irogers@google.com>
Tue, 19 Nov 2024 01:16:28 +0000 (17:16 -0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 18 Dec 2024 19:24:32 +0000 (16:24 -0300)
Rewrite the directory iteration to use openat so that large character
arrays aren't needed. The arrays are warned about potential buffer
overflows by GCC when the code exists in a single C file.

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Colin Ian King <colin.i.king@gmail.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ilya Leoshkevich <iii@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Veronika Molnarova <vmolnaro@redhat.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Link: https://lore.kernel.org/r/20241119011644.971342-7-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-script.c
tools/perf/util/path.c
tools/perf/util/path.h

index cc42b472dfffb2e4bd71763443f862b6d7959725..196e2f3438c5b0503e7e9015507d626f059c12e5 100644 (file)
@@ -3535,27 +3535,35 @@ static void free_dlarg(void)
  * which is covered well now. And new parsing code should be added to
  * cover the future complex formats like event groups etc.
  */
-static int check_ev_match(char *dir_name, char *scriptname,
-                       struct perf_session *session)
+static int check_ev_match(int dir_fd, const char *scriptname, struct perf_session *session)
 {
-       char filename[MAXPATHLEN], evname[128];
-       char line[BUFSIZ], *p;
-       struct evsel *pos;
-       int match, len;
+       char line[BUFSIZ];
        FILE *fp;
 
-       scnprintf(filename, MAXPATHLEN, "%s/bin/%s-record", dir_name, scriptname);
+       {
+               char filename[FILENAME_MAX + 5];
+               int fd;
 
-       fp = fopen(filename, "r");
-       if (!fp)
-               return -1;
+               scnprintf(filename, sizeof(filename), "bin/%s-record", scriptname);
+               fd = openat(dir_fd, filename, O_RDONLY);
+               if (fd == -1)
+                       return -1;
+               fp = fdopen(fd, "r");
+               if (!fp)
+                       return -1;
+       }
 
        while (fgets(line, sizeof(line), fp)) {
-               p = skip_spaces(line);
+               char *p = skip_spaces(line);
+
                if (*p == '#')
                        continue;
 
                while (strlen(p)) {
+                       int match, len;
+                       struct evsel *pos;
+                       char evname[128];
+
                        p = strstr(p, "-e");
                        if (!p)
                                break;
@@ -3598,7 +3606,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array, int num,
                 int pathlen)
 {
        struct dirent *script_dirent, *lang_dirent;
-       char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
+       int scripts_dir_fd, lang_dir_fd;
        DIR *scripts_dir, *lang_dir;
        struct perf_session *session;
        struct perf_data data = {
@@ -3607,51 +3615,76 @@ int find_scripts(char **scripts_array, char **scripts_path_array, int num,
        };
        char *temp;
        int i = 0;
+       const char *exec_path = get_argv_exec_path();
 
        session = perf_session__new(&data, NULL);
        if (IS_ERR(session))
                return PTR_ERR(session);
 
-       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
+       {
+               char scripts_path[PATH_MAX];
 
-       scripts_dir = opendir(scripts_path);
+               snprintf(scripts_path, sizeof(scripts_path), "%s/scripts", exec_path);
+               scripts_dir_fd = open(scripts_path, O_DIRECTORY);
+               pr_err("Failed to open directory '%s'", scripts_path);
+               if (scripts_dir_fd == -1) {
+                       perf_session__delete(session);
+                       return -1;
+               }
+       }
+       scripts_dir = fdopendir(scripts_dir_fd);
        if (!scripts_dir) {
+               close(scripts_dir_fd);
                perf_session__delete(session);
                return -1;
        }
 
-       for_each_lang(scripts_path, scripts_dir, lang_dirent) {
-               scnprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path,
-                         lang_dirent->d_name);
+       while ((lang_dirent = readdir(scripts_dir)) != NULL) {
+               if (lang_dirent->d_type != DT_DIR &&
+                   (lang_dirent->d_type == DT_UNKNOWN &&
+                    !is_directory_at(scripts_dir_fd, lang_dirent->d_name)))
+                       continue;
+               if (!strcmp(lang_dirent->d_name, ".") || !strcmp(lang_dirent->d_name, ".."))
+                       continue;
+
 #ifndef HAVE_LIBPERL_SUPPORT
-               if (strstr(lang_path, "perl"))
+               if (strstr(lang_dirent->d_name, "perl"))
                        continue;
 #endif
 #ifndef HAVE_LIBPYTHON_SUPPORT
-               if (strstr(lang_path, "python"))
+               if (strstr(lang_dirent->d_name, "python"))
                        continue;
 #endif
 
-               lang_dir = opendir(lang_path);
-               if (!lang_dir)
+               lang_dir_fd = openat(scripts_dir_fd, lang_dirent->d_name, O_DIRECTORY);
+               if (lang_dir_fd == -1)
                        continue;
-
-               for_each_script(lang_path, lang_dir, script_dirent) {
+               lang_dir = fdopendir(lang_dir_fd);
+               if (!lang_dir) {
+                       close(lang_dir_fd);
+                       continue;
+               }
+               while ((script_dirent = readdir(lang_dir)) != NULL) {
+                       if (script_dirent->d_type == DT_DIR)
+                               continue;
+                       if (script_dirent->d_type == DT_UNKNOWN &&
+                           is_directory_at(lang_dir_fd, script_dirent->d_name))
+                               continue;
                        /* Skip those real time scripts: xxxtop.p[yl] */
                        if (strstr(script_dirent->d_name, "top."))
                                continue;
                        if (i >= num)
                                break;
-                       snprintf(scripts_path_array[i], pathlen, "%s/%s",
-                               lang_path,
+                       scnprintf(scripts_path_array[i], pathlen, "%s/scripts/%s/%s",
+                               exec_path,
+                               lang_dirent->d_name,
                                script_dirent->d_name);
                        temp = strchr(script_dirent->d_name, '.');
                        snprintf(scripts_array[i],
                                (temp - script_dirent->d_name) + 1,
                                "%s", script_dirent->d_name);
 
-                       if (check_ev_match(lang_path,
-                                       scripts_array[i], session))
+                       if (check_ev_match(lang_dir_fd, scripts_array[i], session))
                                continue;
 
                        i++;
index 00adf872bf00ba28c3b0b6f2ca6a6dd5fec3ffdb..9712466c51e2f30efbe622c275c02e3ed4cf2bf8 100644 (file)
@@ -68,6 +68,16 @@ bool is_directory(const char *base_path, const struct dirent *dent)
        return S_ISDIR(st.st_mode);
 }
 
+bool is_directory_at(int dir_fd, const char *path)
+{
+       struct stat st;
+
+       if (fstatat(dir_fd, path, &st, /*flags=*/0))
+               return false;
+
+       return S_ISDIR(st.st_mode);
+}
+
 bool is_executable_file(const char *base_path, const struct dirent *dent)
 {
        char path[PATH_MAX];
index d94902c222223423b7401da9f9df130f3aec3da2..fbafbe7015dd0b3fe473671cbe5f4a85ff6de26d 100644 (file)
@@ -12,6 +12,7 @@ int path__join3(char *bf, size_t size, const char *path1, const char *path2, con
 
 bool is_regular_file(const char *file);
 bool is_directory(const char *base_path, const struct dirent *dent);
+bool is_directory_at(int dir_fd, const char *path);
 bool is_executable_file(const char *base_path, const struct dirent *dent);
 
 #endif /* _PERF_PATH_H */