diff -urp libcap-ng-0.8.2.orig/src/cap-ng.c libcap-ng-0.8.2/src/cap-ng.c --- libcap-ng-0.8.2.orig/src/cap-ng.c 2020-11-20 13:37:57.000000000 -0500 +++ libcap-ng-0.8.2/src/cap-ng.c 2020-11-20 13:57:54.934059250 -0500 @@ -680,6 +680,8 @@ int capng_updatev(capng_act_t action, ca int capng_apply(capng_select_t set) { + int rc = 0; + // Before updating, we expect that the data is initialized to something if (m.state < CAPNG_INIT) return -1; @@ -695,52 +697,78 @@ int capng_apply(capng_select_t set) for (i=0; i <= last_cap; i++) { if (capng_have_capability(CAPNG_BOUNDING_SET, i) == 0) { - if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) <0) - return -2; + if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) <0) { + rc = -2; + goto try_caps; + } } } m.state = CAPNG_APPLIED; - if (get_bounding_set() < 0) - return -3; + if (get_bounding_set() < 0) { + rc = -3; + goto try_caps; + } } else { memcpy(&m, &state, sizeof(m)); /* restore state */ - return -4; + rc = -4; + goto try_caps; } #endif } + + // Try caps is here so that if someone had SELECT_BOTH and we blew up + // doing the bounding set, we at least try to set any capabilities + // before returning in case the caller also doesn't bother checking + // the return code. +try_caps: if (set & CAPNG_SELECT_CAPS) { if (capset((cap_user_header_t)&m.hdr, (cap_user_data_t)&m.data) == 0) m.state = CAPNG_APPLIED; else - return -5; + rc = -5; } - // Put ambient last so that inheritable and permitted are set + + // Most programs do not and should not mess with ambient capabilities. + // Instead of returning here if rc is set, we'll let it try to + // do something with ambient capabilities in hopes that it's lowering + // capabilities. Again, this is for people that don't check their + // return codes. + // + // Do ambient last so that inheritable and permitted are set by the + // time we get here. if (set & CAPNG_SELECT_AMBIENT) { #ifdef PR_CAP_AMBIENT if (capng_have_capabilities(CAPNG_SELECT_AMBIENT) == CAPNG_NONE) { if (prctl(PR_CAP_AMBIENT, - PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0) - return -6; + PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0) { + rc = -6; + goto out; + } } else { unsigned int i; // Clear them all if (prctl(PR_CAP_AMBIENT, - PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0) - return -7; + PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0) { + rc = -7; + goto out; + } for (i=0; i <= last_cap; i++) { if (capng_have_capability(CAPNG_AMBIENT, i)) if (prctl(PR_CAP_AMBIENT, - PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) - return -8; + PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0){ + rc = -8; + goto out; + } } } m.state = CAPNG_APPLIED; #endif } - return 0; +out: + return rc; } #ifdef VFS_CAP_U32