From 15cacf20709c6917c798e298a1e087c0663e5c13 Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Tue, 29 Mar 2022 18:06:18 -0700 Subject: Fix prctl return code/errno handling in libcap. Bug reported by Anderson Toshiyuki Sasaki: https://bugzilla.kernel.org/show_bug.cgi?id=215772 Signed-off-by: Andrew G. Morgan --- libcap/cap_proc.c | 45 +++++++++++++++++++-------------------------- libcap/cap_test.c | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/libcap/cap_proc.c b/libcap/cap_proc.c index 65204bf..0ce5db7 100644 --- a/libcap/cap_proc.c +++ b/libcap/cap_proc.c @@ -135,7 +135,13 @@ static int _libcap_wprctl3(struct syscaller_s *sc, long int pr_cmd, long int arg1, long int arg2) { if (_libcap_overrode_syscalls) { - return sc->three(SYS_prctl, pr_cmd, arg1, arg2); + int result; + result = sc->three(SYS_prctl, pr_cmd, arg1, arg2); + if (result >= 0) { + return result; + } + errno = -result; + return -1; } return prctl(pr_cmd, arg1, arg2, 0, 0, 0); } @@ -145,7 +151,13 @@ static int _libcap_wprctl6(struct syscaller_s *sc, long int arg3, long int arg4, long int arg5) { if (_libcap_overrode_syscalls) { - return sc->six(SYS_prctl, pr_cmd, arg1, arg2, arg3, arg4, arg5); + int result; + result = sc->six(SYS_prctl, pr_cmd, arg1, arg2, arg3, arg4, arg5); + if (result >= 0) { + return result; + } + errno = -result; + return -1; } return prctl(pr_cmd, arg1, arg2, arg3, arg4, arg5); } @@ -271,26 +283,12 @@ int capsetp(pid_t pid, cap_t cap_d) int cap_get_bound(cap_value_t cap) { - int result; - - result = prctl(PR_CAPBSET_READ, pr_arg(cap), pr_arg(0)); - if (result < 0) { - errno = -result; - return -1; - } - return result; + return prctl(PR_CAPBSET_READ, pr_arg(cap), pr_arg(0)); } static int _cap_drop_bound(struct syscaller_s *sc, cap_value_t cap) { - int result; - - result = _libcap_wprctl3(sc, PR_CAPBSET_DROP, pr_arg(cap), pr_arg(0)); - if (result < 0) { - errno = -result; - return -1; - } - return result; + return _libcap_wprctl3(sc, PR_CAPBSET_DROP, pr_arg(cap), pr_arg(0)); } /* drop a capability from the bounding set */ @@ -316,7 +314,7 @@ int cap_get_ambient(cap_value_t cap) static int _cap_set_ambient(struct syscaller_s *sc, cap_value_t cap, cap_flag_value_t set) { - int result, val; + int val; switch (set) { case CAP_SET: val = PR_CAP_AMBIENT_RAISE; @@ -328,13 +326,8 @@ static int _cap_set_ambient(struct syscaller_s *sc, errno = EINVAL; return -1; } - result = _libcap_wprctl6(sc, PR_CAP_AMBIENT, pr_arg(val), pr_arg(cap), - pr_arg(0), pr_arg(0), pr_arg(0)); - if (result < 0) { - errno = -result; - return -1; - } - return result; + return _libcap_wprctl6(sc, PR_CAP_AMBIENT, pr_arg(val), pr_arg(cap), + pr_arg(0), pr_arg(0), pr_arg(0)); } /* diff --git a/libcap/cap_test.c b/libcap/cap_test.c index 39df261..68b6a13 100644 --- a/libcap/cap_test.c +++ b/libcap/cap_test.c @@ -254,6 +254,21 @@ drop_c: return retval; } +static int test_prctl(void) +{ + int ret, retval=0; + errno = 0; + ret = cap_get_bound((cap_value_t) -1); + if (ret != -1) { + printf("cap_get_bound(-1) did not return error: %d\n", ret); + retval = -1; + } else if (errno != EINVAL) { + perror("cap_get_bound(-1) errno != EINVAL"); + retval = -1; + } + return retval; +} + int main(int argc, char **argv) { int result = 0; @@ -269,6 +284,9 @@ int main(int argc, char **argv) { printf("test_alloc: being called\n"); fflush(stdout); result = test_alloc() | result; + printf("test_prctl: being called\n"); + fflush(stdout); + result = test_prctl() | result; printf("tested\n"); fflush(stdout); -- cgit 1.2.3-korg