Kernel is using capabilities instead of uid and euid to restrict access to
kernel pointers and tracing facilities. This patch series updates the perf to
better match the security model used by the kernel.
This series enables instructions in Documentation/admin-guide/perf-security.rst
to actually work, even when kernel.perf_event_paranoid=2 and
kernel.kptr_restrict=1.
The series consists of three patches:
01: perf: Add capability-related utilities
Add utility functions to check capabilities and perf_event_paranoid checks.
02: perf: Use CAP_SYS_ADMIN with perf_event_paranoid checks
Replace the use of euid==0 with a check for CAP_SYS_ADMIN whenever
perf_event_paranoid level is verified.
03: perf: Use CAP_SYSLOG with kptr_restrict checks
Replace the use of uid and euid with a check for CAP_SYSLOG when
kptr_restrict is verified (similar to kernel/kallsyms.c and lib/vsprintf.c).
Consult perf_event_paranoid when kptr_restrict==0 (see kernel/kallsyms.c).
I tested this by following Documentation/admin-guide/perf-security.rst
guidelines and setting sysctls:
kernel.perf_event_paranoid=2
kernel.kptr_restrict=1
As an unpriviledged user who is in perf_users group (setup via instructions
above), I executed:
perf record -a -- sleep 1
Without the patch, perf record did not capture any kernel functions.
With the patch, perf included all kernel funcitons.
Igor Lubashev (3):
perf: Add capability-related utilities
perf: Use CAP_SYS_ADMIN with perf_event_paranoid checks
perf: Use CAP_SYSLOG with kptr_restrict checks
tools/perf/Makefile.config | 2 +-
tools/perf/arch/arm/util/cs-etm.c | 3 ++-
tools/perf/arch/arm64/util/arm-spe.c | 3 ++-
tools/perf/arch/x86/util/intel-bts.c | 3 ++-
tools/perf/arch/x86/util/intel-pt.c | 2 +-
tools/perf/util/Build | 1 +
tools/perf/util/cap.c | 24 ++++++++++++++++++++++++
tools/perf/util/cap.h | 10 ++++++++++
tools/perf/util/event.h | 1 +
tools/perf/util/evsel.c | 2 +-
tools/perf/util/python-ext-sources | 1 +
tools/perf/util/symbol.c | 15 +++++++++++----
tools/perf/util/util.c | 9 +++++++++
13 files changed, 66 insertions(+), 10 deletions(-)
create mode 100644 tools/perf/util/cap.c
create mode 100644 tools/perf/util/cap.h
--
2.7.4
Kernel is using CAP_SYSLOG capcbility instead of uid==0 and euid==0 when
checking kptr_restrict. Make perf do the same.
Also, the kernel is a more restrictive than "no restrictions" in case of
kptr_restrict==0, so add the same logic to perf.
Signed-off-by: Igor Lubashev <[email protected]>
---
tools/perf/util/symbol.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 5cbad55cd99d..fd68dae3f58e 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <linux/capability.h>
#include <linux/kernel.h>
#include <linux/mman.h>
#include <linux/time64.h>
@@ -15,8 +16,10 @@
#include <inttypes.h>
#include "annotate.h"
#include "build-id.h"
+#include "cap.h"
#include "util.h"
#include "debug.h"
+#include "event.h"
#include "machine.h"
#include "map.h"
#include "symbol.h"
@@ -889,7 +892,11 @@ bool symbol__restricted_filename(const char *filename,
{
bool restricted = false;
- if (symbol_conf.kptr_restrict) {
+ /* Per kernel/kallsyms.c:
+ * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG
+ */
+ if (symbol_conf.kptr_restrict ||
+ (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG))) {
char *r = realpath(filename, NULL);
if (r != NULL) {
@@ -2100,9 +2107,9 @@ static bool symbol__read_kptr_restrict(void)
char line[8];
if (fgets(line, sizeof(line), fp) != NULL)
- value = ((geteuid() != 0) || (getuid() != 0)) ?
- (atoi(line) != 0) :
- (atoi(line) == 2);
+ value = perf_cap__capable(CAP_SYSLOG) ?
+ (atoi(line) >= 2) :
+ (atoi(line) != 0);
fclose(fp);
}
--
2.7.4
On 03.07.2019 3:10, Igor Lubashev wrote:
> Kernel is using capabilities instead of uid and euid to restrict access to
> kernel pointers and tracing facilities. This patch series updates the perf to
> better match the security model used by the kernel.
>
> This series enables instructions in Documentation/admin-guide/perf-security.rst
> to actually work, even when kernel.perf_event_paranoid=2 and
> kernel.kptr_restrict=1.
>
> The series consists of three patches:
>
> 01: perf: Add capability-related utilities
> Add utility functions to check capabilities and perf_event_paranoid checks.
>
> 02: perf: Use CAP_SYS_ADMIN with perf_event_paranoid checks
> Replace the use of euid==0 with a check for CAP_SYS_ADMIN whenever
> perf_event_paranoid level is verified.
>
> 03: perf: Use CAP_SYSLOG with kptr_restrict checks
> Replace the use of uid and euid with a check for CAP_SYSLOG when
> kptr_restrict is verified (similar to kernel/kallsyms.c and lib/vsprintf.c).
> Consult perf_event_paranoid when kptr_restrict==0 (see kernel/kallsyms.c).
>
> I tested this by following Documentation/admin-guide/perf-security.rst
> guidelines and setting sysctls:
>
> kernel.perf_event_paranoid=2
> kernel.kptr_restrict=1
>
> As an unpriviledged user who is in perf_users group (setup via instructions
> above), I executed:
> perf record -a -- sleep 1
>
> Without the patch, perf record did not capture any kernel functions.
> With the patch, perf included all kernel funcitons.
Acked-by: Alexey Budankov <[email protected]>
Valuable contribution, thanks! And I see the continuation of the effort started
in this patch set. Some dedicated CAP_SYS_PERFMON capability could be introduced
and used for performance monitoring related security checks, as in the kernel as
in the user mode, because CAP_SYS_ADMIN grants much wider credentials that are
required, at least for Perf related monitoring and, yet more, CAP_SYS_ADMIN could
be unloaded addressing the concerns here [1]:
CAP_SYS_ADMIN
Note: this capability is overloaded; see Notes to kernel developers, below.
...
Notes to kernel developers:
When adding a new kernel feature that should be governed by a
capability, consider the following points.
* The goal of capabilities is divide the power of superuser into
pieces, such that if a program that has one or more capabilities
is compromised, its power to do damage to the system would be less
than the same program running with root privilege.
* You have the choice of either creating a new capability for your
new feature, or associating the feature with one of the existing
capabilities. In order to keep the set of capabilities to a
manageable size, the latter option is preferable, unless there are
compelling reasons to take the former option. (There is also a
technical limit: the size of capability sets is currently limited
to 64 bits.)
. . .
* Don't choose CAP_SYS_ADMIN if you can possibly avoid it! A vast
proportion of existing capability checks are associated with this
capability (see the partial list above). It can plausibly be
called "the new root", since on the one hand, it confers a wide
range of powers, and on the other hand, its broad scope means that
this is the capability that is required by many privileged
programs. Don't make the problem worse. The only new features
that should be associated with CAP_SYS_ADMIN are ones that closely
match existing uses in that silo.
* If you have determined that it really is necessary to create a new
capability for your feature, don't make or name it as a "single-
use" capability. Thus, for example, the addition of the highly
specific CAP_SYS_PACCT was probably a mistake. Instead, try to
identify and name your new capability as a broader silo into which
other related future use cases might fit.”
Regards,
Alexey
[1] http://man7.org/linux/man-pages/man7/capabilities.7.html
>
> Igor Lubashev (3):
> perf: Add capability-related utilities
> perf: Use CAP_SYS_ADMIN with perf_event_paranoid checks
> perf: Use CAP_SYSLOG with kptr_restrict checks
>
> tools/perf/Makefile.config | 2 +-
> tools/perf/arch/arm/util/cs-etm.c | 3 ++-
> tools/perf/arch/arm64/util/arm-spe.c | 3 ++-
> tools/perf/arch/x86/util/intel-bts.c | 3 ++-
> tools/perf/arch/x86/util/intel-pt.c | 2 +-
> tools/perf/util/Build | 1 +
> tools/perf/util/cap.c | 24 ++++++++++++++++++++++++
> tools/perf/util/cap.h | 10 ++++++++++
> tools/perf/util/event.h | 1 +
> tools/perf/util/evsel.c | 2 +-
> tools/perf/util/python-ext-sources | 1 +
> tools/perf/util/symbol.c | 15 +++++++++++----
> tools/perf/util/util.c | 9 +++++++++
> 13 files changed, 66 insertions(+), 10 deletions(-)
> create mode 100644 tools/perf/util/cap.c
> create mode 100644 tools/perf/util/cap.h
>
Kernel requires CAP_SYS_ADMIN instead of euid==0 to mount debugfs for ftrace.
Make perf require the same.
Signed-off-by: Igor Lubashev <[email protected]>
---
tools/perf/builtin-ftrace.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 9c228c55e1fb..2f632b11ebba 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -13,6 +13,7 @@
#include <signal.h>
#include <fcntl.h>
#include <poll.h>
+#include <linux/capability.h>
#include "debug.h"
#include <subcmd/parse-options.h>
@@ -21,6 +22,7 @@
#include "target.h"
#include "cpumap.h"
#include "thread_map.h"
+#include "util/cap.h"
#include "util/config.h"
@@ -281,7 +283,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
.events = POLLIN,
};
- if (geteuid() != 0) {
+ if (!perf_cap__capable(CAP_SYS_ADMIN)) {
pr_err("ftrace only works for root!\n");
return -1;
}
--
2.7.4