Explorar o código

Merge remote-tracking branch 'upstream/debian/experimental' into feature/acq-trans

Michael Vogt %!s(int64=11) %!d(string=hai) anos
pai
achega
e31a89e668

+ 12 - 0
apt-pkg/acquire-method.cc

@@ -118,6 +118,18 @@ void pkgAcqMethod::Fail(string Err,bool Transient)
 
    std::cout << "\n" << std::flush;
 }
+									/*}}}*/
+// AcqMethod::DropPrivsOrDie - Drop privileges or die		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqMethod::DropPrivsOrDie()
+{
+   if (!DropPrivs()) {
+      Fail(false);
+      exit(112);	/* call the european emergency number */
+   }
+}
+
 									/*}}}*/
 // AcqMethod::URIStart - Indicate a download is starting		/*{{{*/
 // ---------------------------------------------------------------------

+ 1 - 1
apt-pkg/acquire-method.h

@@ -105,7 +105,7 @@ class pkgAcqMethod
    
    pkgAcqMethod(const char *Ver,unsigned long Flags = 0);
    virtual ~pkgAcqMethod() {};
-
+   void DropPrivsOrDie();
    private:
    APT_HIDDEN void Dequeue();
 };

+ 81 - 4
apt-pkg/contrib/fileutl.cc

@@ -48,6 +48,7 @@
 #include <errno.h>
 #include <glob.h>
 #include <pwd.h>
+#include <grp.h>
 
 #include <set>
 #include <algorithm>
@@ -64,6 +65,10 @@
 #include <endian.h>
 #include <stdint.h>
 
+#if __gnu_linux__
+#include <sys/prctl.h>
+#endif
+
 #include <apti18n.h>
 									/*}}}*/
 
@@ -2170,17 +2175,89 @@ bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode)
 
 bool DropPrivs()
 {
-   if (getuid() != 0)
+   // uid will be 0 in the end, but gid might be different anyway
+   uid_t old_uid = getuid();
+   gid_t old_gid = getgid();
+
+   if (old_uid != 0)
+      return true;
+   if(_config->FindB("Debug::NoDropPrivs", false) == true)
       return true;
 
-   const std::string nobody = _config->Find("APT::User::Nobody", "nobody");
-   struct passwd *pw = getpwnam(nobody.c_str());
+   const std::string toUser = _config->Find("APT::Sandbox::User", "_apt");
+   struct passwd *pw = getpwnam(toUser.c_str());
    if (pw == NULL)
-      return _error->Warning("No user %s, can not drop rights", nobody.c_str());
+      return _error->Error("No user %s, can not drop rights", toUser.c_str());
+
+#if __gnu_linux__
+   // see prctl(2), needs linux3.5
+   int ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0,0, 0);
+   if(ret < 0)
+      _error->Warning("PR_SET_NO_NEW_PRIVS failed with %i", ret);
+#endif
+   // Do not change the order here, it might break things
+   if (setgroups(1, &pw->pw_gid))
+      return _error->Errno("setgroups", "Failed to setgroups");
+
+   if (setegid(pw->pw_gid) != 0)
+      return _error->Errno("setegid", "Failed to setegid");
+
    if (setgid(pw->pw_gid) != 0)
       return _error->Errno("setgid", "Failed to setgid");
+
    if (setuid(pw->pw_uid) != 0)
       return _error->Errno("setuid", "Failed to setuid");
 
+   // the seteuid() is probably uneeded (at least thats what the linux
+   // man-page says about setuid(2)) but we cargo culted it anyway
+   if (seteuid(pw->pw_uid) != 0)
+      return _error->Errno("seteuid", "Failed to seteuid");
+
+   // Verify that the user has only a single group, and the correct one
+   gid_t groups[1];
+   if (getgroups(1, groups) != 1)
+      return _error->Errno("getgroups", "Could not get new groups");
+   if (groups[0] != pw->pw_gid)
+      return _error->Error("Could not switch group");
+
+   // Verify that gid, egid, uid, and euid changed
+   if (getgid() != pw->pw_gid)
+      return _error->Error("Could not switch group");
+   if (getegid() != pw->pw_gid)
+      return _error->Error("Could not switch effective group");
+   if (getuid() != pw->pw_uid)
+      return _error->Error("Could not switch user");
+   if (geteuid() != pw->pw_uid)
+      return _error->Error("Could not switch effective user");
+
+#ifdef HAVE_GETRESUID
+   // verify that the saved set-user-id was changed as well
+   uid_t ruid = 0;
+   uid_t euid = 0;
+   uid_t suid = 0;
+   if (getresuid(&ruid, &euid, &suid))
+      return _error->Errno("getresuid", "Could not get saved set-user-ID");
+   if (suid != pw->pw_uid)
+      return _error->Error("Could not switch saved set-user-ID");
+#endif
+
+#ifdef HAVE_GETRESGID
+   // verify that the saved set-group-id was changed as well
+   gid_t rgid = 0;
+   gid_t egid = 0;
+   gid_t sgid = 0;
+   if (getresgid(&rgid, &egid, &sgid))
+      return _error->Errno("getresuid", "Could not get saved set-group-ID");
+   if (sgid != pw->pw_gid)
+      return _error->Error("Could not switch saved set-group-ID");
+#endif
+
+   // Check that uid and gid changes do not work anymore
+   if (pw->pw_gid != old_gid && (setgid(old_gid) != -1 || setegid(old_gid) != -1))
+      return _error->Error("Could restore a gid to root, privilege dropping did not work");
+
+   if (pw->pw_uid != old_uid && (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
+      return _error->Error("Could restore a uid to root, privilege dropping did not work");
+
    return true;
 }

+ 11 - 1
apt-pkg/contrib/fileutl.h

@@ -199,7 +199,17 @@ bool ExecWait(pid_t Pid,const char *Name,bool Reap = false);
 // check if the given file starts with a PGP cleartext signature
 bool StartsWithGPGClearTextSignature(std::string const &FileName);
 
-// process releated
+/**
+ * \brief Drop privileges
+ *
+ * Drop the privileges to the user _apt (or the one specified in
+ * APT::Sandbox::User). This does not set the supplementary group
+ * ids up correctly, it only uses the default group. Also prevent
+ * the process from gaining any new privileges afterwards, at least
+ * on Linux.
+ *
+ * \return true on success, false on failure with _error set
+ */
 bool DropPrivs();
 
 // File string manipulators

+ 4 - 0
buildlib/config.h.in

@@ -28,6 +28,10 @@
 /* If there is no socklen_t, define this for the netdb shim */
 #undef NEED_SOCKLEN_T_DEFINE
 
+/* We need the getresuid() function */
+#undef HAVE_GETRESUID
+#undef HAVE_GETRESGID
+
 /* Define to the size of the filesize containing structures */
 #undef _FILE_OFFSET_BITS
 

+ 6 - 0
configure.ac

@@ -172,6 +172,12 @@ AC_EGREP_HEADER(h_errno, netdb.h, [AC_MSG_RESULT(normal)],
        [AC_MSG_ERROR("not found.")])
    ])
 
+
+dnl check for setuid checking function
+AC_CHECK_FUNCS(getresuid getresgid)
+AC_SUBST(HAVE_GETRESUID)
+AC_SUBST(HAVE_GETRESGID)
+
 dnl Check for doxygen
 AC_PATH_PROG(DOXYGEN, doxygen)
 

+ 7 - 0
debian/apt.postinst

@@ -26,6 +26,13 @@ case "$1" in
 	    fi
 	fi
 
+        # add unprivileged user for the apt methods
+        adduser --force-badname --system --no-create-home \
+            --quiet _apt || true
+        chown -R _apt:root \
+            /var/lib/apt/lists \
+            /var/cache/apt/archives
+
         # ensure tighter permissons on the logs, see LP: #975199
         if dpkg --compare-versions "$2" lt-nl 0.9.7.7; then
             # ensure permissions are right

+ 19 - 0
debian/changelog

@@ -1,3 +1,22 @@
+apt (1.1~exp3) experimental; urgency=medium
+
+  [ Michael Vogt ]
+  * merged changes from debian/sid up to 1.0.9.1
+  * Make /var/lib/apt/lists and /var/cache/apt/archives owned
+    by the new _apt user
+  * Drop Privileges in the following acquire methods:
+     copy, http, https, ftp, gpgv, gzip/bzip2/lzma/xz 
+  * DropPrivs: Improvements based on feedback from error@debian.org
+
+  [ Julian Andres Klode ]
+  * DropPriv: Really call seteuid and not setuid, and add more checks
+  * Use _apt as our unprivileged user name
+  * DropPrivs: Also check for saved set-user-ID and set-group-ID
+  * methods: Fail if we cannot drop privileges
+  * DropPrivs: Also check for saved set-user-ID and set-group-ID
+
+ -- Michael Vogt <mvo@debian.org>  Wed, 24 Sep 2014 22:30:09 +0200
+
 apt (1.1~exp2) experimental; urgency=medium
 
   [ Guillem Jover ]

+ 2 - 0
methods/copy.cc

@@ -127,5 +127,7 @@ int main()
    setlocale(LC_ALL, "");
 
    CopyMethod Mth;
+
+   Mth.DropPrivsOrDie();
    return Mth.Run();
 }

+ 3 - 0
methods/ftp.cc

@@ -1131,6 +1131,9 @@ int main(int, const char *argv[])
    }
    
    FtpMethod Mth;
+
+   // no more active ftp, sorry
+   Mth.DropPrivsOrDie();
    
    return Mth.Run();
 }

+ 4 - 1
methods/gpgv.cc

@@ -5,6 +5,7 @@
 #include <apt-pkg/error.h>
 #include <apt-pkg/gpgv.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/fileutl.h>
 
 #include <ctype.h>
 #include <errno.h>
@@ -261,8 +262,10 @@ bool GPGVMethod::Fetch(FetchItem *Itm)
 int main()
 {
    setlocale(LC_ALL, "");
-   
+
    GPGVMethod Mth;
 
+   Mth.DropPrivsOrDie();
+
    return Mth.Run();
 }

+ 3 - 0
methods/gzip.cc

@@ -139,5 +139,8 @@ int main(int, char *argv[])
    ++Prog;
 
    GzipMethod Mth;
+
+   Mth.DropPrivsOrDie();
+
    return Mth.Run();
 }

+ 4 - 1
methods/http_main.cc

@@ -1,5 +1,6 @@
 #include <config.h>
-
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/error.h>
 #include <signal.h>
 
 #include "http.h"
@@ -13,5 +14,7 @@ int main()
    signal(SIGPIPE, SIG_IGN);
 
    HttpMethod Mth;
+
+   Mth.DropPrivsOrDie();
    return Mth.Loop();
 }

+ 2 - 0
methods/https.cc

@@ -446,6 +446,8 @@ int main()
    HttpsMethod Mth;
    curl_global_init(CURL_GLOBAL_SSL) ;
 
+   Mth.DropPrivsOrDie();
+
    return Mth.Run();
 }