Add DropPrivileges().

DropPrivileges() is used in exception_port_tool, so that when it is
installed as a setuid executable, it only uses elevated privileges to
obtain a task port for its -p option, and then relinquishes those
privileges.

It is difficult to provide a test for this function, because it must be
running setuid or setgid in order to do anything interesting. However,
the function contains its own CHECKs to verify that it behaves properly.

R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/727053002
This commit is contained in:
Mark Mentovai 2014-11-14 18:44:19 -05:00
parent de3c46c6b3
commit 49d7fdba9a
4 changed files with 120 additions and 0 deletions

View File

@ -34,6 +34,7 @@
#include "util/mach/mach_extensions.h"
#include "util/mach/symbolic_constants_mach.h"
#include "util/mach/task_for_pid.h"
#include "util/posix/drop_privileges.h"
#include "util/stdlib/string_number_conversion.h"
namespace crashpad {
@ -503,6 +504,10 @@ int ExceptionPortToolMain(int argc, char* argv[]) {
alternate_task_owner.reset(options.alternate_task);
}
// This tool may have been installed as a setuid binary so that TaskForPID()
// could succeed. Drop any privileges now that theyre no longer necessary.
DropPrivileges();
MachSendRightPool mach_send_right_pool;
// Show bootstrap services requested.

View File

@ -0,0 +1,73 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <unistd.h>
#include "base/logging.h"
#include "build/build_config.h"
namespace crashpad {
void DropPrivileges() {
gid_t gid = getgid();
uid_t uid = getuid();
#if defined(OS_MACOSX)
// Based on the POSIX.1-2008 2013 edition documentation for setreuid() and
// setregid(), setreuid() and setregid() alone should be sufficient to drop
// privileges. The standard specifies that the saved ID should be set to the
// effective ID whenever the real ID is not -1, and whenever the effective ID
// is set not equal to the real ID. This code never specifies -1, so the
// setreuid() and setregid() alone should work according to the standard.
//
// In practice, on Mac OS X, setuid() and setgid() (or seteuid() and
// setegid()) must be called first, otherwise, setreuid() and setregid() do
// not alter the saved IDs, leaving open the possibility for future privilege
// escalation. This bug is filed as radar 18987552.
gid_t egid = getegid();
PCHECK(setgid(gid) == 0) << "setgid";
PCHECK(setregid(gid, gid) == 0) << "setregid";
uid_t euid = geteuid();
PCHECK(setuid(uid) == 0) << "setuid";
PCHECK(setreuid(uid, uid) == 0) << "setreuid";
if (uid != 0) {
// Because the setXid()+setreXid() interface to change IDs is fragile,
// ensure that privileges cannot be regained. This can only be done if the
// real user ID (and now the effective user ID as well) is not root, because
// root always has permission to change identity.
if (euid != uid) {
CHECK_EQ(seteuid(euid), -1);
}
if (egid != gid) {
CHECK_EQ(setegid(egid), -1);
}
}
#elif defined(OS_LINUX)
PCHECK(setresgid(gid, gid, gid) == 0) << "setresgid";
PCHECK(setresuid(uid, uid, uid) == 0) << "setresuid";
// Dont check to see if privileges can be regained on Linux, because on
// Linux, its not as simple as ensuring that this cant be done if non-root.
// Instead, the ability to change user and group IDs are controlled by the
// CAP_SETUID and CAP_SETGID capabilities, which may be granted to non-root
// processes. Since the setresXid() interface is well-defined, it shouldnt be
// necessary to perform any additional checking anyway.
#else
#error Port this function to your system.
#endif
}
} // namespace crashpad

View File

@ -0,0 +1,40 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_UTIL_POSIX_DROP_PRIVILEGES_H_
#define CRASHPAD_UTIL_POSIX_DROP_PRIVILEGES_H_
namespace crashpad {
//! \brief Permanently drops privileges conferred by being a setuid or setgid
//! executable.
//!
//! The effective user ID and saved set-user ID are set to the real user ID,
//! negating any effects of being a setuid executable. The effective group ID
//! and saved set-group ID are set to the real group ID, negating any effects of
//! being a setgid executable. Because the saved set-user ID and saved set-group
//! ID are reset, there is no way to restore the prior privileges, and the drop
//! is permanent.
//!
//! This function drops privileges correctly when running setuid root and in
//! other circumstances, including when running setuid non-root. If the program
//! is not a setuid or setgid executable, this function has no effect.
//!
//! No changes are made to the supplementary group list, which is normally not
//! altered for setuid or setgid executables.
void DropPrivileges();
} // namespace crashpad
#endif // CRASHPAD_UTIL_POSIX_DROP_PRIVILEGES_H_

View File

@ -84,6 +84,8 @@
'numeric/in_range_cast.h',
'numeric/int128.h',
'numeric/safe_assignment.h',
'posix/drop_privileges.cc',
'posix/drop_privileges.h',
'posix/process_info.h',
'posix/process_info_mac.cc',
'posix/symbolic_constants_posix.cc',