diff options
-rw-r--r-- | apt-pkg/acquire-method.cc | 12 | ||||
-rw-r--r-- | apt-pkg/acquire-method.h | 2 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.cc | 85 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.h | 12 | ||||
-rw-r--r-- | buildlib/config.h.in | 4 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | debian/apt.postinst | 7 | ||||
-rw-r--r-- | debian/changelog | 19 | ||||
-rw-r--r-- | methods/copy.cc | 2 | ||||
-rw-r--r-- | methods/ftp.cc | 3 | ||||
-rw-r--r-- | methods/gpgv.cc | 5 | ||||
-rw-r--r-- | methods/gzip.cc | 3 | ||||
-rw-r--r-- | methods/http_main.cc | 5 | ||||
-rw-r--r-- | methods/https.cc | 2 |
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(); } |