summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <mvo@ubuntu.com>2014-09-25 12:33:26 +0200
committerMichael Vogt <mvo@ubuntu.com>2014-09-25 12:33:26 +0200
commite31a89e668596ea86c8f3a08429cd2f48286e734 (patch)
tree417a694cc8dea17a352c2534f6a9e1f7b23178c6
parent03bfbc965443393b92b2d6d82613472fa3a5067f (diff)
parent47d278dc7184606f751d015689e0c49eccde4547 (diff)
Merge remote-tracking branch 'upstream/debian/experimental' into feature/acq-trans
-rw-r--r--apt-pkg/acquire-method.cc12
-rw-r--r--apt-pkg/acquire-method.h2
-rw-r--r--apt-pkg/contrib/fileutl.cc85
-rw-r--r--apt-pkg/contrib/fileutl.h12
-rw-r--r--buildlib/config.h.in4
-rw-r--r--configure.ac6
-rw-r--r--debian/apt.postinst7
-rw-r--r--debian/changelog19
-rw-r--r--methods/copy.cc2
-rw-r--r--methods/ftp.cc3
-rw-r--r--methods/gpgv.cc5
-rw-r--r--methods/gzip.cc3
-rw-r--r--methods/http_main.cc5
-rw-r--r--methods/https.cc2
14 files changed, 159 insertions, 8 deletions
diff --git a/apt-pkg/acquire-method.cc b/apt-pkg/acquire-method.cc
index e4a937d1d..82f2fb3ce 100644
--- a/apt-pkg/acquire-method.cc
+++ b/apt-pkg/acquire-method.cc
@@ -119,6 +119,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 /*{{{*/
// ---------------------------------------------------------------------
/* */
diff --git a/apt-pkg/acquire-method.h b/apt-pkg/acquire-method.h
index cbf79f860..cdeecc9a7 100644
--- a/apt-pkg/acquire-method.h
+++ b/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();
};
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
index 6b8f04dea..e81f32a52 100644
--- a/apt-pkg/contrib/fileutl.cc
+++ b/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;
}
diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h
index a8e255b86..9dd29eb9e 100644
--- a/apt-pkg/contrib/fileutl.h
+++ b/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
diff --git a/buildlib/config.h.in b/buildlib/config.h.in
index 6b72fb393..c0fd2e8c6 100644
--- a/buildlib/config.h.in
+++ b/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
diff --git a/configure.ac b/configure.ac
index 89950fccd..5d0e0a9db 100644
--- a/configure.ac
+++ b/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)
diff --git a/debian/apt.postinst b/debian/apt.postinst
index fd3e273bb..fab026504 100644
--- a/debian/apt.postinst
+++ b/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
diff --git a/debian/changelog b/debian/changelog
index 32447d5e1..acbe7ddba 100644
--- a/debian/changelog
+++ b/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 ]
diff --git a/methods/copy.cc b/methods/copy.cc
index 30a3f4a51..faf330ace 100644
--- a/methods/copy.cc
+++ b/methods/copy.cc
@@ -127,5 +127,7 @@ int main()
setlocale(LC_ALL, "");
CopyMethod Mth;
+
+ Mth.DropPrivsOrDie();
return Mth.Run();
}
diff --git a/methods/ftp.cc b/methods/ftp.cc
index 66787a7be..a658b5657 100644
--- a/methods/ftp.cc
+++ b/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();
}
diff --git a/methods/gpgv.cc b/methods/gpgv.cc
index 30fd217bd..72e4c7987 100644
--- a/methods/gpgv.cc
+++ b/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();
}
diff --git a/methods/gzip.cc b/methods/gzip.cc
index df3f8828f..7ffcda60f 100644
--- a/methods/gzip.cc
+++ b/methods/gzip.cc
@@ -139,5 +139,8 @@ int main(int, char *argv[])
++Prog;
GzipMethod Mth;
+
+ Mth.DropPrivsOrDie();
+
return Mth.Run();
}
diff --git a/methods/http_main.cc b/methods/http_main.cc
index 3b346a514..f21a5709c 100644
--- a/methods/http_main.cc
+++ b/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();
}
diff --git a/methods/https.cc b/methods/https.cc
index 0499af0c5..a74d2a38b 100644
--- a/methods/https.cc
+++ b/methods/https.cc
@@ -446,6 +446,8 @@ int main()
HttpsMethod Mth;
curl_global_init(CURL_GLOBAL_SSL) ;
+ Mth.DropPrivsOrDie();
+
return Mth.Run();
}