]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
pinger: drop capabilities on Linux
authorYuriy M. Kaminskiy <yumkam@gmail.com>
Tue, 29 Mar 2016 16:56:38 +0000 (05:56 +1300)
committerAmos Jeffries <squid3@treenet.co.nz>
Tue, 29 Mar 2016 16:56:38 +0000 (05:56 +1300)
On linux, it is possible to install pinger helper with only CAP_NET_RAW
raised instead of full setuid-root:

 (setcap cap_net_raw+ep /path/to/pinger && chmod u-s /path/to/pinger) || :

However, pinger only drops setuid/setgid, and won't drop capabilities
after sockets are opened (when it is setuid-root, setuid(getuid()) also
drops capabilities, no code changes necessary; however, if it is only
setcap'ed, setuid() is no-op).

Fix is minimally tested, seems to work fine with both/either `setcap`
and `chmod u+s`; non-linux/non-libcap configurations should not be
affected).

* Also fixes errno debug outputs.

src/icmp/pinger.cc

index f9d409c7dfedf8637f9e12a11d56d401129a51a1..f5ee11c55cb9ed4865a6da3dbb15532ed9be654c 100644 (file)
@@ -162,18 +162,46 @@ main(int argc, char *argv[])
     max_fd = max(max_fd, squid_link);
 
     if (setgid(getgid()) < 0) {
-        debugs(42, DBG_CRITICAL, "FATAL: pinger: setgid(" << getgid() << ") failed: " << xstrerror());
+        int xerrno = errno;
+        debugs(42, DBG_CRITICAL, "FATAL: pinger: setgid(" << getgid() << ") failed: " << xstrerr(xerrno));
         icmp4.Close();
         icmp6.Close();
         exit (1);
     }
     if (setuid(getuid()) < 0) {
-        debugs(42, DBG_CRITICAL, "FATAL: pinger: setuid(" << getuid() << ") failed: " << xstrerror());
+        int xerrno = errno;
+        debugs(42, DBG_CRITICAL, "FATAL: pinger: setuid(" << getuid() << ") failed: " << xstrerr(xerrno));
         icmp4.Close();
         icmp6.Close();
         exit (1);
     }
 
+#if USE_LIBCAP
+    // Drop remaining capabilities (if installed as non-setuid setcap cap_net_raw=ep).
+    // If pinger binary was installed setuid root, setuid() above already dropped all
+    // capabilities, and this is no-op.
+    cap_t caps;
+    caps = cap_init();
+    if (!caps) {
+        int xerrno = errno;
+        debugs(42, DBG_CRITICAL, "FATAL: pinger: cap_init() failed: " << xstrerr(xerrno));
+        icmp4.Close();
+        icmp6.Close();
+        exit (1);
+    } else {
+        if (cap_set_proc(caps) != 0) {
+            int xerrno = errno;
+            // cap_set_proc(cap_init()) is expected to never fail
+            debugs(42, DBG_CRITICAL, "FATAL: pinger: cap_set_proc(none) failed: " << xstrerr(xerrno));
+            cap_free(caps);
+            icmp4.Close();
+            icmp6.Close();
+            exit (1);
+        }
+        cap_free(caps);
+    }
+#endif
+
     last_check_time = squid_curtime;
 
     for (;;) {
@@ -192,7 +220,8 @@ main(int argc, char *argv[])
         getCurrentTime();
 
         if (x < 0) {
-            debugs(42, DBG_CRITICAL, HERE << " FATAL Shutdown. select()==" << x << ", ERR: " << xstrerror());
+            int xerrno = errno;
+            debugs(42, DBG_CRITICAL, HERE << " FATAL Shutdown. select()==" << x << ", ERR: " << xstrerr(xerrno));
             control.Close();
             exit(1);
         }