diff mbox series

[bpf-next,2/3] bpf: selftests: Remove libcap usage from test_verifier

Message ID 20220316014854.2257030-1-kafai@fb.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series Remove libcap dependency from bpf selftests | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 7 maintainers not CCed: netdev@vger.kernel.org songliubraving@fb.com linux-kselftest@vger.kernel.org shuah@kernel.org yhs@fb.com john.fastabend@gmail.com kpsingh@kernel.org
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning CHECK: Prefer using the BIT_ULL macro
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next fail VM_Test

Commit Message

Martin KaFai Lau March 16, 2022, 1:48 a.m. UTC
This patch removes the libcap usage from test_verifier.
The cap_*_effective() helpers added in the earlier patch are
used instead.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
---
 tools/testing/selftests/bpf/Makefile        |  3 +-
 tools/testing/selftests/bpf/test_verifier.c | 89 ++++++---------------
 2 files changed, 28 insertions(+), 64 deletions(-)

Comments

Shung-Hsi Yu March 17, 2022, 2:18 a.m. UTC | #1
On Tue, Mar 15, 2022 at 06:48:54PM -0700, Martin KaFai Lau wrote:
> This patch removes the libcap usage from test_verifier.
> The cap_*_effective() helpers added in the earlier patch are
> used instead.
> 
> Signed-off-by: Martin KaFai Lau <kafai@fb.com>
> ---
>  tools/testing/selftests/bpf/Makefile        |  3 +-
>  tools/testing/selftests/bpf/test_verifier.c | 89 ++++++---------------
>  2 files changed, 28 insertions(+), 64 deletions(-)
> 
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index fe12b4f5fe20..1c6e55740019 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -195,6 +195,7 @@ $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ)
>  CGROUP_HELPERS	:= $(OUTPUT)/cgroup_helpers.o
>  TESTING_HELPERS	:= $(OUTPUT)/testing_helpers.o
>  TRACE_HELPERS	:= $(OUTPUT)/trace_helpers.o
> +CAP_HELPERS	:= $(OUTPUT)/cap_helpers.o
>  
>  $(OUTPUT)/test_dev_cgroup: $(CGROUP_HELPERS) $(TESTING_HELPERS)
>  $(OUTPUT)/test_skb_cgroup_id_user: $(CGROUP_HELPERS) $(TESTING_HELPERS)
> @@ -211,7 +212,7 @@ $(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
>  $(OUTPUT)/xdping: $(TESTING_HELPERS)
>  $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
>  $(OUTPUT)/test_maps: $(TESTING_HELPERS)
> -$(OUTPUT)/test_verifier: $(TESTING_HELPERS)
> +$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS)
>  
>  BPFTOOL ?= $(DEFAULT_BPFTOOL)
>  $(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile)    \
> diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
> index 92e3465fbae8..091848662b7a 100644
> --- a/tools/testing/selftests/bpf/test_verifier.c
> +++ b/tools/testing/selftests/bpf/test_verifier.c
> @@ -22,8 +22,7 @@
>  #include <limits.h>
>  #include <assert.h>
>  
> -#include <sys/capability.h>
> -
> +#include <linux/capability.h>
>  #include <linux/unistd.h>
>  #include <linux/filter.h>
>  #include <linux/bpf_perf_event.h>
> @@ -42,6 +41,7 @@
>  #  define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1
>  # endif
>  #endif
> +#include "cap_helpers.h"
>  #include "bpf_rand.h"
>  #include "bpf_util.h"
>  #include "test_btf.h"
> @@ -62,6 +62,10 @@
>  #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS	(1 << 0)
>  #define F_LOAD_WITH_STRICT_ALIGNMENT		(1 << 1)
>  
> +/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
> +#define ADMIN_CAPS (1ULL << CAP_NET_ADMIN |	\
> +		    1ULL << CAP_PERFMON |	\
> +		    1ULL << CAP_BPF)
>  #define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
>  static bool unpriv_disabled = false;
>  static int skips;
> @@ -973,47 +977,19 @@ struct libcap {
>  
>  static int set_admin(bool admin)
>  {
> -	cap_t caps;
> -	/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
> -	const cap_value_t cap_net_admin = CAP_NET_ADMIN;
> -	const cap_value_t cap_sys_admin = CAP_SYS_ADMIN;
> -	struct libcap *cap;
> -	int ret = -1;
> -
> -	caps = cap_get_proc();
> -	if (!caps) {
> -		perror("cap_get_proc");
> -		return -1;
> -	}
> -	cap = (struct libcap *)caps;
> -	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_sys_admin, CAP_CLEAR)) {
> -		perror("cap_set_flag clear admin");
> -		goto out;
> -	}
> -	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_admin,
> -				admin ? CAP_SET : CAP_CLEAR)) {
> -		perror("cap_set_flag set_or_clear net");
> -		goto out;
> -	}
> -	/* libcap is likely old and simply ignores CAP_BPF and CAP_PERFMON,
> -	 * so update effective bits manually
> -	 */
> +	int err;
> +
>  	if (admin) {
> -		cap->data[1].effective |= 1 << (38 /* CAP_PERFMON */ - 32);
> -		cap->data[1].effective |= 1 << (39 /* CAP_BPF */ - 32);
> +		err = cap_enable_effective(ADMIN_CAPS, NULL);
> +		if (err)
> +			perror("cap_enable_effective(ADMIN_CAPS)");
>  	} else {
> -		cap->data[1].effective &= ~(1 << (38 - 32));
> -		cap->data[1].effective &= ~(1 << (39 - 32));
> -	}
> -	if (cap_set_proc(caps)) {
> -		perror("cap_set_proc");
> -		goto out;
> +		err = cap_disable_effective(ADMIN_CAPS, NULL);
> +		if (err)
> +			perror("cap_disable_effective(ADMIN_CAPS)");
>  	}
> -	ret = 0;
> -out:
> -	if (cap_free(caps))
> -		perror("cap_free");
> -	return ret;
> +
> +	return err;
>  }
>  
>  static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val,
> @@ -1291,31 +1267,18 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
>  
>  static bool is_admin(void)
>  {
> -	cap_flag_value_t net_priv = CAP_CLEAR;
> -	bool perfmon_priv = false;
> -	bool bpf_priv = false;
> -	struct libcap *cap;
> -	cap_t caps;
> -
> -#ifdef CAP_IS_SUPPORTED
> -	if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) {
> -		perror("cap_get_flag");
> -		return false;
> -	}
> -#endif
> -	caps = cap_get_proc();
> -	if (!caps) {
> -		perror("cap_get_proc");
> +	__u64 caps;
> +
> +	/* The test checks for finer cap as CAP_NET_ADMIN,
> +	 * CAP_PERFMON, and CAP_BPF instead of CAP_SYS_ADMIN.
> +	 * Thus, disable CAP_SYS_ADMIN at the beginning.
> +	 */
> +	if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) {
> +		perror("cap_disable_effective(CAP_SYS_ADMIN)");
>  		return false;
>  	}

Seems slightly strange for a is_* function to have the side effect of
disabling capability, also, this change of behavior in is_admin() is not in
the commit message.

Maybe a better place to disable CAP_SYS_ADMIN is at the beginning of main()?
That seems to be the only place is_admin() is called.

> -	cap = (struct libcap *)caps;
> -	bpf_priv = cap->data[1].effective & (1 << (39/* CAP_BPF */ - 32));
> -	perfmon_priv = cap->data[1].effective & (1 << (38/* CAP_PERFMON */ - 32));
> -	if (cap_get_flag(caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &net_priv))
> -		perror("cap_get_flag NET");
> -	if (cap_free(caps))
> -		perror("cap_free");
> -	return bpf_priv && perfmon_priv && net_priv == CAP_SET;
> +
> +	return (caps & ADMIN_CAPS) == ADMIN_CAPS;
>  }
>  
>  static void get_unpriv_disabled()
> -- 
> 2.30.2
> 
>
Shung-Hsi Yu March 17, 2022, 7:04 a.m. UTC | #2
On Thu, Mar 17, 2022 at 10:18:45AM +0800, Shung-Hsi Yu wrote:
> On Tue, Mar 15, 2022 at 06:48:54PM -0700, Martin KaFai Lau wrote:
> > This patch removes the libcap usage from test_verifier.
> > The cap_*_effective() helpers added in the earlier patch are
> > used instead.
> > 
> > Signed-off-by: Martin KaFai Lau <kafai@fb.com>
> > ---
> >  tools/testing/selftests/bpf/Makefile        |  3 +-
> >  tools/testing/selftests/bpf/test_verifier.c | 89 ++++++---------------
> >  2 files changed, 28 insertions(+), 64 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> > index fe12b4f5fe20..1c6e55740019 100644
> > --- a/tools/testing/selftests/bpf/Makefile
> > +++ b/tools/testing/selftests/bpf/Makefile
> > @@ -195,6 +195,7 @@ $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ)
> >  CGROUP_HELPERS	:= $(OUTPUT)/cgroup_helpers.o
> >  TESTING_HELPERS	:= $(OUTPUT)/testing_helpers.o
> >  TRACE_HELPERS	:= $(OUTPUT)/trace_helpers.o
> > +CAP_HELPERS	:= $(OUTPUT)/cap_helpers.o
> >  
> >  $(OUTPUT)/test_dev_cgroup: $(CGROUP_HELPERS) $(TESTING_HELPERS)
> >  $(OUTPUT)/test_skb_cgroup_id_user: $(CGROUP_HELPERS) $(TESTING_HELPERS)
> > @@ -211,7 +212,7 @@ $(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
> >  $(OUTPUT)/xdping: $(TESTING_HELPERS)
> >  $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
> >  $(OUTPUT)/test_maps: $(TESTING_HELPERS)
> > -$(OUTPUT)/test_verifier: $(TESTING_HELPERS)
> > +$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS)
> >  
> >  BPFTOOL ?= $(DEFAULT_BPFTOOL)
> >  $(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile)    \
> > diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
> > index 92e3465fbae8..091848662b7a 100644
> > --- a/tools/testing/selftests/bpf/test_verifier.c
> > +++ b/tools/testing/selftests/bpf/test_verifier.c
> > @@ -22,8 +22,7 @@
> >  #include <limits.h>
> >  #include <assert.h>
> >  
> > -#include <sys/capability.h>
> > -
> > +#include <linux/capability.h>
> >  #include <linux/unistd.h>
> >  #include <linux/filter.h>
> >  #include <linux/bpf_perf_event.h>
> > @@ -42,6 +41,7 @@
> >  #  define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1
> >  # endif
> >  #endif
> > +#include "cap_helpers.h"
> >  #include "bpf_rand.h"
> >  #include "bpf_util.h"
> >  #include "test_btf.h"
> > @@ -62,6 +62,10 @@
> >  #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS	(1 << 0)
> >  #define F_LOAD_WITH_STRICT_ALIGNMENT		(1 << 1)
> >  
> > +/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
> > +#define ADMIN_CAPS (1ULL << CAP_NET_ADMIN |	\
> > +		    1ULL << CAP_PERFMON |	\
> > +		    1ULL << CAP_BPF)
> >  #define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
> >  static bool unpriv_disabled = false;
> >  static int skips;
> > @@ -973,47 +977,19 @@ struct libcap {
> >  
> >  static int set_admin(bool admin)
> >  {
> > -	cap_t caps;
> > -	/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
> > -	const cap_value_t cap_net_admin = CAP_NET_ADMIN;
> > -	const cap_value_t cap_sys_admin = CAP_SYS_ADMIN;
> > -	struct libcap *cap;
> > -	int ret = -1;
> > -
> > -	caps = cap_get_proc();
> > -	if (!caps) {
> > -		perror("cap_get_proc");
> > -		return -1;
> > -	}
> > -	cap = (struct libcap *)caps;
> > -	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_sys_admin, CAP_CLEAR)) {
> > -		perror("cap_set_flag clear admin");
> > -		goto out;
> > -	}
> > -	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_admin,
> > -				admin ? CAP_SET : CAP_CLEAR)) {
> > -		perror("cap_set_flag set_or_clear net");
> > -		goto out;
> > -	}
> > -	/* libcap is likely old and simply ignores CAP_BPF and CAP_PERFMON,
> > -	 * so update effective bits manually
> > -	 */
> > +	int err;
> > +
> >  	if (admin) {
> > -		cap->data[1].effective |= 1 << (38 /* CAP_PERFMON */ - 32);
> > -		cap->data[1].effective |= 1 << (39 /* CAP_BPF */ - 32);
> > +		err = cap_enable_effective(ADMIN_CAPS, NULL);
> > +		if (err)
> > +			perror("cap_enable_effective(ADMIN_CAPS)");
> >  	} else {
> > -		cap->data[1].effective &= ~(1 << (38 - 32));
> > -		cap->data[1].effective &= ~(1 << (39 - 32));
> > -	}
> > -	if (cap_set_proc(caps)) {
> > -		perror("cap_set_proc");
> > -		goto out;
> > +		err = cap_disable_effective(ADMIN_CAPS, NULL);
> > +		if (err)
> > +			perror("cap_disable_effective(ADMIN_CAPS)");
> >  	}
> > -	ret = 0;
> > -out:
> > -	if (cap_free(caps))
> > -		perror("cap_free");
> > -	return ret;
> > +
> > +	return err;
> >  }
> >  
> >  static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val,
> > @@ -1291,31 +1267,18 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
> >  
> >  static bool is_admin(void)
> >  {
> > -	cap_flag_value_t net_priv = CAP_CLEAR;
> > -	bool perfmon_priv = false;
> > -	bool bpf_priv = false;
> > -	struct libcap *cap;
> > -	cap_t caps;
> > -
> > -#ifdef CAP_IS_SUPPORTED
> > -	if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) {
> > -		perror("cap_get_flag");
> > -		return false;
> > -	}
> > -#endif
> > -	caps = cap_get_proc();
> > -	if (!caps) {
> > -		perror("cap_get_proc");
> > +	__u64 caps;
> > +
> > +	/* The test checks for finer cap as CAP_NET_ADMIN,
> > +	 * CAP_PERFMON, and CAP_BPF instead of CAP_SYS_ADMIN.
> > +	 * Thus, disable CAP_SYS_ADMIN at the beginning.
> > +	 */
> > +	if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) {
> > +		perror("cap_disable_effective(CAP_SYS_ADMIN)");
> >  		return false;
> >  	}
> 
> Seems slightly strange for a is_* function to have the side effect of
> disabling capability, also, this change of behavior in is_admin() is not in
> the commit message.
> 
> Maybe a better place to disable CAP_SYS_ADMIN is at the beginning of main()?
> That seems to be the only place is_admin() is called.

Just realized there's a v2 and it's already merged. Sorry for the noise.

Shung-Hsi

> > -	cap = (struct libcap *)caps;
> > -	bpf_priv = cap->data[1].effective & (1 << (39/* CAP_BPF */ - 32));
> > -	perfmon_priv = cap->data[1].effective & (1 << (38/* CAP_PERFMON */ - 32));
> > -	if (cap_get_flag(caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &net_priv))
> > -		perror("cap_get_flag NET");
> > -	if (cap_free(caps))
> > -		perror("cap_free");
> > -	return bpf_priv && perfmon_priv && net_priv == CAP_SET;
> > +
> > +	return (caps & ADMIN_CAPS) == ADMIN_CAPS;
> >  }
> >  
> >  static void get_unpriv_disabled()
> > -- 
> > 2.30.2
> > 
> >
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index fe12b4f5fe20..1c6e55740019 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -195,6 +195,7 @@  $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ)
 CGROUP_HELPERS	:= $(OUTPUT)/cgroup_helpers.o
 TESTING_HELPERS	:= $(OUTPUT)/testing_helpers.o
 TRACE_HELPERS	:= $(OUTPUT)/trace_helpers.o
+CAP_HELPERS	:= $(OUTPUT)/cap_helpers.o
 
 $(OUTPUT)/test_dev_cgroup: $(CGROUP_HELPERS) $(TESTING_HELPERS)
 $(OUTPUT)/test_skb_cgroup_id_user: $(CGROUP_HELPERS) $(TESTING_HELPERS)
@@ -211,7 +212,7 @@  $(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
 $(OUTPUT)/xdping: $(TESTING_HELPERS)
 $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
 $(OUTPUT)/test_maps: $(TESTING_HELPERS)
-$(OUTPUT)/test_verifier: $(TESTING_HELPERS)
+$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS)
 
 BPFTOOL ?= $(DEFAULT_BPFTOOL)
 $(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile)    \
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index 92e3465fbae8..091848662b7a 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -22,8 +22,7 @@ 
 #include <limits.h>
 #include <assert.h>
 
-#include <sys/capability.h>
-
+#include <linux/capability.h>
 #include <linux/unistd.h>
 #include <linux/filter.h>
 #include <linux/bpf_perf_event.h>
@@ -42,6 +41,7 @@ 
 #  define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1
 # endif
 #endif
+#include "cap_helpers.h"
 #include "bpf_rand.h"
 #include "bpf_util.h"
 #include "test_btf.h"
@@ -62,6 +62,10 @@ 
 #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS	(1 << 0)
 #define F_LOAD_WITH_STRICT_ALIGNMENT		(1 << 1)
 
+/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
+#define ADMIN_CAPS (1ULL << CAP_NET_ADMIN |	\
+		    1ULL << CAP_PERFMON |	\
+		    1ULL << CAP_BPF)
 #define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
 static bool unpriv_disabled = false;
 static int skips;
@@ -973,47 +977,19 @@  struct libcap {
 
 static int set_admin(bool admin)
 {
-	cap_t caps;
-	/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
-	const cap_value_t cap_net_admin = CAP_NET_ADMIN;
-	const cap_value_t cap_sys_admin = CAP_SYS_ADMIN;
-	struct libcap *cap;
-	int ret = -1;
-
-	caps = cap_get_proc();
-	if (!caps) {
-		perror("cap_get_proc");
-		return -1;
-	}
-	cap = (struct libcap *)caps;
-	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_sys_admin, CAP_CLEAR)) {
-		perror("cap_set_flag clear admin");
-		goto out;
-	}
-	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_admin,
-				admin ? CAP_SET : CAP_CLEAR)) {
-		perror("cap_set_flag set_or_clear net");
-		goto out;
-	}
-	/* libcap is likely old and simply ignores CAP_BPF and CAP_PERFMON,
-	 * so update effective bits manually
-	 */
+	int err;
+
 	if (admin) {
-		cap->data[1].effective |= 1 << (38 /* CAP_PERFMON */ - 32);
-		cap->data[1].effective |= 1 << (39 /* CAP_BPF */ - 32);
+		err = cap_enable_effective(ADMIN_CAPS, NULL);
+		if (err)
+			perror("cap_enable_effective(ADMIN_CAPS)");
 	} else {
-		cap->data[1].effective &= ~(1 << (38 - 32));
-		cap->data[1].effective &= ~(1 << (39 - 32));
-	}
-	if (cap_set_proc(caps)) {
-		perror("cap_set_proc");
-		goto out;
+		err = cap_disable_effective(ADMIN_CAPS, NULL);
+		if (err)
+			perror("cap_disable_effective(ADMIN_CAPS)");
 	}
-	ret = 0;
-out:
-	if (cap_free(caps))
-		perror("cap_free");
-	return ret;
+
+	return err;
 }
 
 static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val,
@@ -1291,31 +1267,18 @@  static void do_test_single(struct bpf_test *test, bool unpriv,
 
 static bool is_admin(void)
 {
-	cap_flag_value_t net_priv = CAP_CLEAR;
-	bool perfmon_priv = false;
-	bool bpf_priv = false;
-	struct libcap *cap;
-	cap_t caps;
-
-#ifdef CAP_IS_SUPPORTED
-	if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) {
-		perror("cap_get_flag");
-		return false;
-	}
-#endif
-	caps = cap_get_proc();
-	if (!caps) {
-		perror("cap_get_proc");
+	__u64 caps;
+
+	/* The test checks for finer cap as CAP_NET_ADMIN,
+	 * CAP_PERFMON, and CAP_BPF instead of CAP_SYS_ADMIN.
+	 * Thus, disable CAP_SYS_ADMIN at the beginning.
+	 */
+	if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) {
+		perror("cap_disable_effective(CAP_SYS_ADMIN)");
 		return false;
 	}
-	cap = (struct libcap *)caps;
-	bpf_priv = cap->data[1].effective & (1 << (39/* CAP_BPF */ - 32));
-	perfmon_priv = cap->data[1].effective & (1 << (38/* CAP_PERFMON */ - 32));
-	if (cap_get_flag(caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &net_priv))
-		perror("cap_get_flag NET");
-	if (cap_free(caps))
-		perror("cap_free");
-	return bpf_priv && perfmon_priv && net_priv == CAP_SET;
+
+	return (caps & ADMIN_CAPS) == ADMIN_CAPS;
 }
 
 static void get_unpriv_disabled()