1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
/* SPDX-License-Identifier: MIT */
/* SPDX-FileCopyrightText: (c) Copyright 2024 Andrew Bower <andrew@bower.uk> */
#include <linux/prctl.h>
#include <sys/capability.h>
#include "xchpst.h"
#include "options.h"
bool set_capabilities_bounding_set(void) {
int rc;
if (opt.cap_bounds_op == CAP_OP_KEEP) {
int i, max = cap_max_bits();
cap_bits_t b = 1ull << (max - 1);
for (i = max - 1; b; i--, b >>= 1) {
if ((opt.cap_bounds & b) == 0 &&
cap_get_bound(i) == 1) {
if (is_verbose())
fprintf(stderr, "dropping capability %s\n", cap_to_name(i));
rc = cap_drop_bound(i);
if (rc == -1) {
perror("cap_drop_bound");
return false;
}
} else if (is_debug()) {
fprintf(stderr, "keeping capability %s\n", cap_to_name(i));
}
}
} else if (opt.cap_bounds_op == CAP_OP_DROP) {
int i, max = cap_max_bits();
cap_bits_t b = 1ull << (max - 1);
for (i = max - 1; b; i--, b >>= 1) {
if (opt.cap_bounds & b) {
if (is_verbose())
fprintf(stderr, "dropping capability %s\n", cap_to_name(i));
rc = cap_drop_bound(i);
if (rc == -1) {
perror("cap_drop_bound");
return false;
}
}
}
}
return true;
}
/* Drop effective and permitted capabilities,
* make capabilities inheritable and
* add them to the ambient set ahead of execve(). */
bool drop_capabilities(void) {
cap_value_t max = cap_max_bits();
cap_bits_t bits = 1ull << (max - 1);
cap_bits_t make_ambient = 0;
cap_flag_value_t fv;
cap_value_t cap;
cap_t caps;
bool success = false;
if (opt.caps_op == CAP_OP_DROP) {
fv = CAP_CLEAR;
caps = cap_get_proc();
} else {
fv = CAP_SET;
caps = cap_get_proc(); /* not _init() so we can print diagnostics */
}
if (caps == NULL) {
perror("could not get init capabilities");
goto fail0;
}
if (is_verbose()) {
char *capstr = cap_to_text(caps, NULL);
fprintf(stderr, "initial capabilities: %s\n", cap_to_text(caps, NULL));
cap_free(capstr);
}
if (fv == CAP_SET)
cap_clear(caps);
for (cap = max - 1; bits; cap--, bits >>= 1) {
if (opt.caps & bits) {
if (is_verbose())
fprintf(stderr, "%s capability %s\n",
opt.caps_op == CAP_OP_KEEP ? "keeping" : "dropping",
cap_to_name(cap));
if (fv == CAP_SET)
make_ambient |= (1ull << cap);
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, fv) == -1 ||
cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, fv) == -1 ||
cap_set_flag(caps, CAP_PERMITTED, 1, &cap, fv) == -1) {
perror("cap_set_flag");
goto fail;
}
} else if (opt.caps_op == CAP_OP_DROP) {
cap_flag_value_t rdv = CAP_CLEAR;
cap_get_flag(caps, cap, CAP_PERMITTED, &rdv);
if (rdv == CAP_SET) {
make_ambient |= (1ull << cap);
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) == -1 ||
cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_SET) == -1 ||
cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_SET) == -1) {
perror("cap_set_flag");
goto fail;
}
}
}
}
if (is_verbose()) {
char *capstr = cap_to_text(caps, NULL);
fprintf(stderr, "setting capabilities to: %s\n", cap_to_text(caps, NULL));
cap_free(capstr);
}
if (cap_set_proc(caps) == -1) {
perror("setting permitted, effective and inheritable capabilities");
goto fail;
}
if (is_verbose()) {
cap_free(caps);
caps = cap_get_proc();
char *capstr = cap_to_text(caps, NULL);
fprintf(stderr, "final capabilities: %s\n", cap_to_text(caps, NULL));
cap_free(capstr);
}
bits = 1ull << (max - 1);
for (cap = max - 1; bits; cap--, bits >>= 1) {
if (make_ambient & bits) {
if (cap_set_ambient(cap, CAP_SET) == -1) {
perror("setting ambient capabilities");
goto fail;
}
}
}
success = true;
fail:
cap_free(caps);
fail0:
return success;
}
|