[distcc] Re: PATH problem 2

Martin Pool mbp at samba.org
Mon Jul 21 07:32:29 GMT 2003


On 11 Jul 2003, Wayne Davison <wayned at users.sourceforge.net> wrote:
> I was imagining doing a pre-scan of the PATH, outputting the warnings to
> stderr before we detach so the user sees them right away (but only in
> non-inetd mode -- we'd have to use the log if inetd called us), and then
> just using the PATH and let the chips fall where they may.  

I think it really would be better to do it at runtime, when we know
the real compiler name.  

For people doing mostly cross compiles, checking for "cc" may not help
much, and errors at startup may not be very visible.

>  - Some people want to have distccd call ccache, so that needs to be
>    possible (somehow).

Yes.  I think it's probably better just to allow that.  The patch
below puts out a trace message that can be used to work it out if
people wonder.

>  - Where would the warnings get output if they occurred at compiler-
>    exec time?  In the log I suppose?

They get to the client in SERR.

 How about this patch for the server half of the problem, in
 conjunction with removing the dcc_trim_path from the server entirely?

--- serve.c.~1.113.~	2003-07-18 11:45:55.000000000 +1000
+++ serve.c	2003-07-21 17:26:04.000000000 +1000
@@ -68,6 +68,7 @@
 #ifdef HAVE_SYS_SIGNAL_H
 #  include <sys/signal.h>
 #endif /* HAVE_SYS_SIGNAL_H */
+#include <sys/param.h>
 
 #include "distcc.h"
 #include "trace.h"
@@ -174,6 +175,73 @@ static char *dcc_input_tmpnam(char * ori
 
 
 /**
+ * Find the absolute path for the first occurrence of @p compiler_name on the
+ * PATH.  Print a warning if it looks like a symlink to distcc.
+ *
+ * We want to guard against somebody accidentally running the server with a
+ * masqueraded compiler on its $PATH.  The worst that's likely to happen here
+ * is wasting some time running a distcc or ccache client that does nothing,
+ * so it's not a big deal.  (This could be easy to do if it's on the default
+ * PATH and they start the daemon from the command line.)
+ *
+ * At the moment we don't look for the compiler too.
+ **/
+static int dcc_check_compiler_masq(char *compiler_name)
+{
+    const char *envpath, *newpath, *p, *n;
+    char *buf = NULL;
+    struct stat sb;
+    int len;
+    char linkbuf[MAXPATHLEN];
+
+    if (compiler_name[0] == '/') 
+        return 0;
+    
+    if (!(envpath = getenv("PATH"))) {
+        rs_trace("PATH seems not to be defined");
+        return 0;
+    }
+
+    for (n = p = envpath, newpath = NULL; *n; p = n) {
+        n = strchr(p, ':');
+        if (n)
+            len = n++ - p;
+        else {
+            len = strlen(p);
+            n = p + len;
+        }
+        if (asprintf(&buf, "%.*s/%s", len, p, compiler_name) == -1) {
+            rs_log_crit("asnprintf failed");
+            return EXIT_DISTCC_FAILED;
+        }
+
+        if (lstat(buf, &sb) == -1)
+            continue;           /* ENOENT, EACCESS, etc */
+        if (!S_ISLNK(sb.st_mode)) {
+            rs_trace("%s is not a symlink", buf);
+            break;              /* found it */
+        }
+        if ((len = readlink(buf, linkbuf, sizeof linkbuf)) <= 0)
+            continue;
+        linkbuf[len] = '\0';
+        
+        if (strstr(linkbuf, "distcc")) {
+            rs_log_warning("%s on distccd's path is really a link to %s",
+                           buf, linkbuf);
+            break;              /* but use it anyhow */
+        } else {
+            rs_trace("%s is a safe symlink to %s", buf, linkbuf);
+            break;              /* found it */
+        }
+    }
+
+    free(buf);
+    return 0;
+}
+
+
+
+/**
  * Read a request, run the compiler, and send a response.
  **/
 static int dcc_run_job(int in_fd,
@@ -223,7 +291,11 @@ static int dcc_run_job(int in_fd,
         || (ret = dcc_set_output(argv, temp_o)))
         goto out_cleanup;
 
-    if ((compile_ret = dcc_spawn_child(argv, &cc_pid, "/dev/null", out_fname, err_fname))
+    if ((ret = dcc_check_compiler_masq(argv[0])))
+        goto out_cleanup;
+    
+    if ((compile_ret = dcc_spawn_child(argv, &cc_pid,
+                                       "/dev/null", out_fname, err_fname))
         || (compile_ret = dcc_collect_child("cc", cc_pid, &status))) {
         /* We didn't get around to finding a wait status from the actual compiler */
         status = W_EXITCODE(compile_ret, 0);


-- 
Martin 



More information about the distcc mailing list