Compare commits

...

No commits in common. "c8" and "c9s" have entirely different histories.
c8 ... c9s

19 changed files with 929 additions and 778 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/libcap-2.48.tar.gz
/libcap-*.tar.gz

View File

@ -1 +1 @@
c81102815c481257e53168e83b8849bc9f154d54 SOURCES/libcap-2.48.tar.gz
c81102815c481257e53168e83b8849bc9f154d54 libcap-2.48.tar.gz

View File

@ -1,37 +0,0 @@
diff --color -ru a/libcap/cap_text.c b/libcap/cap_text.c
--- a/libcap/cap_text.c 2021-02-05 06:52:17.000000000 +0100
+++ b/libcap/cap_text.c 2021-12-15 13:03:44.993774400 +0100
@@ -15,7 +15,7 @@
#define LIBCAP_PLEASE_INCLUDE_ARRAY
#include "libcap.h"
-static char const *_cap_names[__CAP_BITS] = LIBCAP_CAP_NAMES;
+extern char const *_cap_names[__CAP_BITS];
#include <ctype.h>
#include <limits.h>
diff --color -ru a/libcap/_makenames.c b/libcap/_makenames.c
--- a/libcap/_makenames.c 2021-02-05 06:52:17.000000000 +0100
+++ b/libcap/_makenames.c 2021-12-15 12:47:07.921408357 +0100
@@ -66,17 +66,17 @@
"#define __CAP_NAME_SIZE %d\n"
"\n"
"#ifdef LIBCAP_PLEASE_INCLUDE_ARRAY\n"
- "#define LIBCAP_CAP_NAMES { \\\n", maxcaps, maxlength+1);
+ " char const *_cap_names[__CAP_BITS] = {\n", maxcaps, maxlength+1);
for (i=0; i<maxcaps; ++i) {
if (pointers[i]) {
- printf(" /* %d */\t\"%s\", \\\n", i, pointers[i]);
+ printf(" /* %d */\t\"%s\",\n", i, pointers[i]);
} else {
- printf(" /* %d */\tNULL,\t\t/* - presently unused */ \\\n", i);
+ printf(" /* %d */\tNULL,\t\t/* - presently unused */\n", i);
}
}
- printf(" }\n"
+ printf(" };\n"
"#endif /* LIBCAP_PLEASE_INCLUDE_ARRAY */\n"
"\n"
"/* END OF FILE */\n");

View File

@ -1,54 +0,0 @@
--- a/libcap/cap_alloc.c 2021-02-05 06:52:17.000000000 +0100
+++ b/libcap/cap_alloc.c 2022-05-17 20:06:53.570560396 +0200
@@ -123,6 +123,10 @@
cap_iab_t cap_iab_init(void) {
__u32 *base = calloc(1, sizeof(__u32) + sizeof(struct cap_iab_s));
+ if (base == NULL) {
+ _cap_debug("out of memory");
+ return NULL;
+ }
*(base++) = CAP_IAB_MAGIC;
return (cap_iab_t) base;
}
@@ -138,6 +142,10 @@
const char * const *envp)
{
__u32 *data = calloc(1, sizeof(__u32) + sizeof(struct cap_launch_s));
+ if (data == NULL) {
+ _cap_debug("out of memory");
+ return NULL;
+ }
*(data++) = CAP_LAUNCH_MAGIC;
struct cap_launch_s *attr = (struct cap_launch_s *) data;
attr->arg0 = arg0;
--- a/libcap/cap_proc.c 2022-05-17 20:07:36.301803359 +0200
+++ b/libcap/cap_proc.c 2022-05-17 20:06:59.238592623 +0200
@@ -677,9 +677,25 @@
*/
cap_iab_t cap_iab_get_proc(void)
{
- cap_iab_t iab = cap_iab_init();
- cap_t current = cap_get_proc();
+ cap_iab_t iab;
+ cap_t current;
+
+ iab = cap_iab_init();
+ if (iab == NULL) {
+ _cap_debug("no memory for IAB tuple");
+ return NULL;
+ }
+
+ current = cap_get_proc();
+ if (current == NULL) {
+ _cap_debug("no memory for cap_t");
+ cap_free(iab);
+ return NULL;
+ }
+
cap_iab_fill(iab, CAP_IAB_INH, current, CAP_INHERITABLE);
+ cap_free(current);
+
cap_value_t c;
for (c = cap_max_bits(); c; ) {
--c;

View File

@ -1,128 +0,0 @@
diff --git a/libcap/cap_proc.c b/libcap/cap_proc.c
--- 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
--- a/libcap/cap_test.c 2021-02-05 06:52:17.000000000 +0100
+++ b/libcap/cap_test.c 2022-05-16 18:24:55.754193142 +0200
@@ -29,11 +29,36 @@
return failed;
}
+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;
+ printf("test_cap_bits: being called\n");
+ fflush(stdout);
result = test_cap_bits() | result;
+ printf("test_prctl: being called\n");
+ fflush(stdout);
+ result = test_prctl() | result;
+ printf("tested\n");
+ fflush(stdout);
+
if (result) {
- printf("test FAILED\n");
+ printf("cap_test FAILED\n");
exit(1);
}
+ printf("cap_test PASS\n");
+ exit(0);
}

View File

@ -1,494 +0,0 @@
diff --color -ru a/libcap/cap_proc.c b/libcap/cap_proc.c
--- a/libcap/cap_proc.c 2022-01-28 12:42:39.726331628 +0100
+++ b/libcap/cap_proc.c 2022-01-28 12:44:05.007936110 +0100
@@ -712,6 +712,10 @@
cap_value_t c;
int raising = 0;
+ if (temp == NULL) {
+ return -1;
+ }
+
for (i = 0; i < _LIBCAP_CAPABILITY_U32S; i++) {
__u32 newI = iab->i[i];
__u32 oldIP = temp->u[i].flat[CAP_INHERITABLE] |
diff --color -ru a/libcap/cap_text.c b/libcap/cap_text.c
--- a/libcap/cap_text.c 2022-01-28 12:42:39.725331609 +0100
+++ b/libcap/cap_text.c 2022-01-28 12:44:05.008936129 +0100
@@ -160,6 +160,7 @@
cap_blks = _LINUX_CAPABILITY_U32S_3;
break;
default:
+ cap_free(res);
errno = EINVAL;
return NULL;
}
@@ -398,6 +399,9 @@
for (n = 0; n < cmb; n++) {
if (getstateflags(caps, n) == t) {
char *this_cap_name = cap_to_name(n);
+ if (this_cap_name == NULL) {
+ return NULL;
+ }
if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
cap_free(this_cap_name);
errno = ERANGE;
@@ -450,6 +454,9 @@
for (n = cmb; n < __CAP_MAXBITS; n++) {
if (getstateflags(caps, n) == t) {
char *this_cap_name = cap_to_name(n);
+ if (this_cap_name == NULL) {
+ return NULL;
+ }
if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
cap_free(this_cap_name);
errno = ERANGE;
@@ -549,6 +556,9 @@
cap_iab_t cap_iab_from_text(const char *text)
{
cap_iab_t iab = cap_iab_init();
+ if (iab == NULL) {
+ return iab;
+ }
if (text != NULL) {
unsigned flags;
for (flags = 0; *text; text++) {
diff --color -ru a/libcap/_makenames.c b/libcap/_makenames.c
--- a/libcap/_makenames.c 2022-01-28 12:42:39.725331609 +0100
+++ b/libcap/_makenames.c 2022-01-28 13:07:28.700817691 +0100
@@ -45,10 +45,14 @@
if (maxcaps <= list[i].index) {
maxcaps = list[i].index + 1;
}
- if (list[i].index >= pointers_avail) {
+ if (pointers == NULL || list[i].index >= pointers_avail) {
int was = pointers_avail * sizeof(char *);
pointers_avail = 2 * list[i].index + 1;
pointers = recalloc(pointers, was, pointers_avail * sizeof(char *));
+ if (pointers == NULL) {
+ perror("unable to continue");
+ exit(1);
+ }
}
pointers[list[i].index] = list[i].name;
int n = strlen(list[i].name);
diff --color -ru a/pam_cap/pam_cap.c b/pam_cap/pam_cap.c
--- a/pam_cap/pam_cap.c 2022-01-28 12:42:39.726331628 +0100
+++ b/pam_cap/pam_cap.c 2022-01-28 12:44:05.009936148 +0100
@@ -64,6 +64,9 @@
}
*groups = calloc(ngrps, sizeof(char *));
+ if (*groups == NULL) {
+ return -1;
+ }
int g_n = 0, i;
for (i = 0; i < ngrps; i++) {
const struct group *g = getgrgid(grps[i]);
@@ -249,7 +252,7 @@
if (!cap_set_proc(cap_s)) {
ok = 1;
}
- goto cleanup_cap_s;
+ goto cleanup_conf;
}
iab = cap_iab_from_text(conf_caps);
@@ -278,10 +281,9 @@
_pam_drop(conf_caps);
cleanup_cap_s:
- if (cap_s) {
- cap_free(cap_s);
- cap_s = NULL;
- }
+ cap_free(cap_s);
+ cap_s = NULL;
+
return ok;
}
diff --color -ru a/progs/capsh.c b/progs/capsh.c
--- a/progs/capsh.c 2021-02-05 06:52:17.000000000 +0100
+++ b/progs/capsh.c 2022-01-28 13:06:15.803465885 +0100
@@ -34,6 +34,35 @@
#define MAX_GROUPS 100 /* max number of supplementary groups for user */
+/* parse a non-negative integer with some error handling */
+static unsigned long nonneg_uint(const char *text, const char *prefix, int *ok)
+{
+ char *remains;
+ unsigned long value;
+ ssize_t len = strlen(text);
+
+ if (len == 0 || *text == '-') {
+ goto fail;
+ }
+ value = strtoul(text, &remains, 0);
+ if (*remains) {
+ goto fail;
+ }
+ if (ok != NULL) {
+ *ok = 1;
+ }
+ return value;
+
+fail:
+ if (ok == NULL) {
+ fprintf(stderr, "%s: want non-negative integer, got \"%s\"\n",
+ prefix, text);
+ exit(1);
+ }
+ *ok = 0;
+ return 0;
+}
+
static char *binary(unsigned long value)
{
static char string[8*sizeof(unsigned long) + 1];
@@ -100,7 +129,16 @@
display_prctl_set("Bounding", cap_get_bound);
display_prctl_set("Ambient", cap_get_ambient);
iab = cap_iab_get_proc();
+ if (iab == NULL) {
+ perror("failed to get IAB for process");
+ exit(1);
+ }
text = cap_iab_to_text(iab);
+ if (text == NULL) {
+ perror("failed to obtain text for IAB");
+ cap_free(iab);
+ exit(1);
+ }
printf("Current IAB: %s\n", text);
cap_free(text);
cap_free(iab);
@@ -336,8 +374,8 @@
*/
static char *find_self(const char *arg0)
{
- int i;
- char *parts, *dir, *scratch;
+ int i, status=1;
+ char *p = NULL, *parts, *dir, *scratch;
const char *path;
for (i = strlen(arg0)-1; i >= 0 && arg0[i] != '/'; i--);
@@ -352,21 +390,45 @@
}
parts = strdup(path);
+ if (parts == NULL) {
+ fprintf(stderr, "insufficient memory for parts of path\n");
+ exit(1);
+ }
+
scratch = malloc(2+strlen(path)+strlen(arg0));
- if (parts == NULL || scratch == NULL) {
+ if (scratch == NULL) {
fprintf(stderr, "insufficient memory for path building\n");
- exit(1);
+ goto free_parts;
}
- for (i=0; (dir = strtok(parts, ":")); parts = NULL) {
+ for (p = parts; (dir = strtok(p, ":")); p = NULL) {
sprintf(scratch, "%s/%s", dir, arg0);
if (access(scratch, X_OK) == 0) {
- return scratch;
+ status = 0;
+ break;
}
}
+ if (status) {
+ fprintf(stderr, "unable to find executable '%s' in PATH\n", arg0);
+ free(scratch);
+ }
- fprintf(stderr, "unable to find executable '%s' in PATH\n", arg0);
- exit(1);
+free_parts:
+ free(parts);
+ if (status) {
+ exit(status);
+ }
+ return scratch;
+}
+
+static long safe_sysconf(int name)
+{
+ long ans = sysconf(name);
+ if (ans <= 0) {
+ fprintf(stderr, "sysconf(%d) returned a non-positive number: %ld\n", name, ans);
+ exit(1);
+ }
+ return ans;
}
int main(int argc, char *argv[], char *envp[])
@@ -378,6 +440,10 @@
child = 0;
char *temp_name = cap_to_name(cap_max_bits() - 1);
+ if (temp_name == NULL) {
+ perror("obtaining highest capability name");
+ exit(1);
+ }
if (temp_name[0] != 'c') {
printf("WARNING: libcap needs an update (cap=%d should have a name).\n",
cap_max_bits() - 1);
@@ -573,7 +639,7 @@
unsigned value;
int set;
- value = strtoul(argv[i]+7, NULL, 0);
+ value = nonneg_uint(argv[i]+7, "invalid --keep value", NULL);
set = prctl(PR_SET_KEEPCAPS, value);
if (set < 0) {
fprintf(stderr, "prctl(PR_SET_KEEPCAPS, %u) failed: %s\n",
@@ -617,7 +683,9 @@
* Given we are now in a new directory tree, its good practice
* to start off in a sane location
*/
- status = chdir("/");
+ if (status == 0) {
+ status = chdir("/");
+ }
cap_free(orig);
@@ -628,7 +696,7 @@
} else if (!strncmp("--secbits=", argv[i], 10)) {
unsigned value;
int status;
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --secbits value", NULL);
status = cap_set_secbits(value);
if (status < 0) {
fprintf(stderr, "failed to set securebits to 0%o/0x%x\n",
@@ -641,7 +709,7 @@
fprintf(stderr, "already forked\n");
exit(1);
}
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --forkfor value", NULL);
if (value == 0) {
goto usage;
}
@@ -657,7 +725,8 @@
pid_t result;
unsigned value;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --killit signo value",
+ NULL);
if (!child) {
fprintf(stderr, "no forked process to kill\n");
exit(1);
@@ -683,7 +752,7 @@
unsigned value;
int status;
- value = strtoul(argv[i]+6, NULL, 0);
+ value = nonneg_uint(argv[i]+6, "invalid --uid value", NULL);
status = setuid(value);
if (status < 0) {
fprintf(stderr, "Failed to set uid=%u: %s\n",
@@ -694,7 +763,7 @@
unsigned value;
int status;
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --cap-uid value", NULL);
status = cap_setuid(value);
if (status < 0) {
fprintf(stderr, "Failed to cap_setuid(%u): %s\n",
@@ -705,7 +774,7 @@
unsigned value;
int status;
- value = strtoul(argv[i]+6, NULL, 0);
+ value = nonneg_uint(argv[i]+6, "invalid --gid value", NULL);
status = setgid(value);
if (status < 0) {
fprintf(stderr, "Failed to set gid=%u: %s\n",
@@ -718,14 +787,14 @@
gid_t *group_list;
int g_count;
- length = sysconf(_SC_GETGR_R_SIZE_MAX);
+ length = safe_sysconf(_SC_GETGR_R_SIZE_MAX);
buf = calloc(1, length);
if (NULL == buf) {
fprintf(stderr, "No memory for [%s] operation\n", argv[i]);
exit(1);
}
- max_groups = sysconf(_SC_NGROUPS_MAX);
+ max_groups = safe_sysconf(_SC_NGROUPS_MAX);
group_list = calloc(max_groups, sizeof(gid_t));
if (NULL == group_list) {
fprintf(stderr, "No memory for gid list\n");
@@ -741,8 +810,7 @@
}
if (!isdigit(*ptr)) {
struct group *g, grp;
- getgrnam_r(ptr, &grp, buf, length, &g);
- if (NULL == g) {
+ if (getgrnam_r(ptr, &grp, buf, length, &g) || NULL == g) {
fprintf(stderr, "Failed to identify gid for group [%s]\n", ptr);
exit(1);
}
@@ -835,6 +903,7 @@
argv[argc] = NULL;
execve(argv[i], argv+i, envp);
fprintf(stderr, "execve '%s' failed!\n", argv[i]);
+ free(argv[i]);
exit(1);
} else if (!strncmp("--shell=", argv[i], 8)) {
shell = argv[i]+8;
@@ -885,7 +954,7 @@
} else if (!strncmp("--is-uid=", argv[i], 9)) {
unsigned value;
uid_t uid;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --is-uid value", NULL);
uid = getuid();
if (uid != value) {
fprintf(stderr, "uid: got=%d, want=%d\n", uid, value);
@@ -894,7 +963,7 @@
} else if (!strncmp("--is-gid=", argv[i], 9)) {
unsigned value;
gid_t gid;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --is-gid value", NULL);
gid = getgid();
if (gid != value) {
fprintf(stderr, "gid: got=%d, want=%d\n", gid, value);
diff --color -ru a/progs/getcap.c b/progs/getcap.c
--- a/progs/getcap.c 2021-02-05 06:52:17.000000000 +0100
+++ b/progs/getcap.c 2022-01-28 12:44:05.009936148 +0100
@@ -110,11 +110,11 @@
for (i=optind; argv[i] != NULL; i++) {
struct stat stbuf;
-
- if (lstat(argv[i], &stbuf) != 0) {
- fprintf(stderr, "%s (%s)\n", argv[i], strerror(errno));
+ char *arg = argv[i];
+ if (lstat(arg, &stbuf) != 0) {
+ fprintf(stderr, "%s (%s)\n", arg, strerror(errno));
} else if (recursive) {
- nftw(argv[i], do_getcap, 20, FTW_PHYS);
+ nftw(arg, do_getcap, 20, FTW_PHYS);
} else {
int tflag = S_ISREG(stbuf.st_mode) ? FTW_F :
(S_ISLNK(stbuf.st_mode) ? FTW_SL : FTW_NS);
diff --color -ru a/progs/setcap.c b/progs/setcap.c
--- a/progs/setcap.c 2021-02-05 06:52:17.000000000 +0100
+++ b/progs/setcap.c 2022-01-28 12:44:05.009936148 +0100
@@ -166,9 +166,12 @@
}
cap_on_file = cap_get_file(*++argv);
-
if (cap_on_file == NULL) {
cap_on_file = cap_from_text("=");
+ if (cap_on_file == NULL) {
+ perror("unable to use missing capability");
+ exit(1);
+ }
}
cmp = cap_compare(cap_on_file, cap_d);
diff --color -ru a/psx/psx.c b/psx/psx.c
--- a/psx/psx.c 2021-02-05 06:52:17.000000000 +0100
+++ b/psx/psx.c 2022-01-28 12:44:05.009936148 +0100
@@ -107,6 +107,10 @@
*/
static void *psx_do_registration(void) {
registered_thread_t *node = calloc(1, sizeof(registered_thread_t));
+ if (node == NULL) {
+ perror("unable to register psx handler");
+ exit(1);
+ }
pthread_mutex_init(&node->mu, NULL);
node->thread = pthread_self();
pthread_setspecific(psx_action_key, node);
@@ -454,6 +458,10 @@
int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg) {
psx_starter_t *starter = calloc(1, sizeof(psx_starter_t));
+ if (starter == NULL) {
+ perror("failed at thread creation");
+ exit(1);
+ }
starter->fn = start_routine;
starter->arg = arg;
/*
diff --color -ru a/tests/libcap_launch_test.c b/tests/libcap_launch_test.c
--- a/tests/libcap_launch_test.c 2021-02-05 06:52:17.000000000 +0100
+++ b/tests/libcap_launch_test.c 2022-01-28 12:44:05.010936167 +0100
@@ -93,6 +93,10 @@
printf("[%d] test should %s\n", i,
v->result ? "generate error" : "work");
cap_launch_t attr = cap_new_launcher(v->args[0], v->args, v->envp);
+ if (attr == NULL) {
+ perror("failed to obtain launcher");
+ exit(1);
+ }
if (v->chroot) {
cap_launcher_set_chroot(attr, v->chroot);
}
diff --color -ru a/tests/libcap_psx_test.c b/tests/libcap_psx_test.c
--- a/tests/libcap_psx_test.c 2021-02-05 06:52:17.000000000 +0100
+++ b/tests/libcap_psx_test.c 2022-01-28 12:55:55.887807887 +0100
@@ -16,8 +16,15 @@
usleep(1234);
pid_t pid = fork();
cap_t start = cap_get_proc();
+ if (start == NULL) {
+ perror("FAILED: unable to start");
+ exit(1);
+ }
if (pid == 0) {
- cap_set_proc(start);
+ if (cap_set_proc(start)) {
+ perror("setting empty caps failed");
+ exit(1);
+ }
exit(0);
}
int res;
@@ -27,6 +34,7 @@
exit(1);
}
cap_set_proc(start);
+ cap_free(start);
return NULL;
}
@@ -35,6 +43,10 @@
printf("hello libcap and libpsx ");
fflush(stdout);
cap_t start = cap_get_proc();
+ if (start == NULL) {
+ perror("FAILED: to actually start");
+ exit(1);
+ }
pthread_t ignored[10];
for (i = 0; i < 10; i++) {
pthread_create(&ignored[i], NULL, thread_fork_exit, NULL);
@@ -42,7 +54,10 @@
for (i = 0; i < 10; i++) {
printf("."); /* because of fork, this may print double */
fflush(stdout); /* try to limit the above effect */
- cap_set_proc(start);
+ if (cap_set_proc(start)) {
+ perror("failed to set proc");
+ exit(1);
+ }
usleep(1000);
}
printf(" PASSED\n");

264
capfaq-0.2.txt Normal file
View File

@ -0,0 +1,264 @@
This is the Linux kernel capabilities FAQ
Its history, to the extent that I am able to reconstruct it is that
v2.0 was posted to the Linux kernel list on 1999/04/02 by Boris
Tobotras. Thanks to Denis Ducamp for forwarding me a copy.
Cheers
Andrew
Linux Capabilities FAQ 0.2
==========================
1) What is a capability?
The name "capabilities" as used in the Linux kernel can be confusing.
First there are Capabilities as defined in computer science. A
capability is a token used by a process to prove that it is allowed to
do an operation on an object. The capability identifies the object
and the operations allowed on that object. A file descriptor is a
capability. You create the file descriptor with the "open" call and
request read or write permissions. Later, when doing a read or write
operation, the kernel uses the file descriptor as an index into a
data structure that indicates what operations are allowed. This is an
efficient way to check permissions. The necessary data structures are
created once during the "open" call. Later read and write calls only
have to do a table lookup. Operations on capabilities include copying
capabilities, transferring capabilities between processes, modifying a
capability, and revoking a capability. Modifying a capability can be
something like taking a read-write filedescriptor and making it
read-only. A capability often has a notion of an "owner" which is
able to invalidate all copies and derived versions of a capability.
Entire OSes are based on this "capability" model, with varying degrees
of purity. There are other ways of implementing capabilities than the
file descriptor model - traditionally special hardware has been used,
but modern systems also use the memory management unit of the CPU.
Then there is something quite different called "POSIX capabilities"
which is what Linux uses. These capabilities are a partitioning of
the all powerful root privilege into a set of distinct privileges (but
look at securelevel emulation to find out that this isn't necessary
the whole truth). Users familiar with VMS or "Trusted" versions of
other UNIX variants will know this under the name "privileges". The
name "capabilities" comes from the now defunct POSIX draft 1003.1e
which used this name.
2) So what is a "POSIX capability"?
A process has three sets of bitmaps called the inheritable(I),
permitted(P), and effective(E) capabilities. Each capability is
implemented as a bit in each of these bitmaps which is either set or
unset. When a process tries to do a privileged operation, the
operating system will check the appropriate bit in the effective set
of the process (instead of checking whether the effective uid of the
process i 0 as is normally done). For example, when a process tries
to set the clock, the Linux kernel will check that the process has the
CAP_SYS_TIME bit (which is currently bit 25) set in its effective set.
The permitted set of the process indicates the capabilities the
process can use. The process can have capabilities set in the
permitted set that are not in the effective set. This indicates that
the process has temporarily disabled this capability. A process is
allowed to set a bit in its effective set only if it is available in
the permitted set. The distinction between effective and permitted
exists so that processes can "bracket" operations that need privilege.
The inheritable capabilities are the capabilities of the current
process that should be inherited by a program executed by the current
process. The permitted set of a process is masked against the
inheritable set during exec(). Nothing special happens during fork()
or clone(). Child processes and threads are given an exact copy of
the capabilities of the parent process.
3) What about other entities in the system? Users, Groups, Files?
Files have capabilities. Conceptually they have the same three
bitmaps that processes have, but to avoid confusion we call them by
other names. Only executable files have capabilities, libraries don't
have capabilities (yet). The three sets are called the allowed set,
the forced set, and the effective set.
The allowed set indicates what capabilities the executable is allowed
to receive from an execing process. This means that during exec(),
the capabilities of the old process are first masked against a set
which indicates what the process gives away (the inheritable set of
the process), and then they are masked against a set which indicates
what capabilities the new process image is allowed to receive (the
allowed set of the executable).
The forced set is a set of capabilities created out of thin air and
given to the process after execing the executable. The forced set is
similar in nature to the setuid feature. In fact, the setuid bit from
the filesystem is "read" as a full forced set by the kernel.
The effective set indicates which bits in the permitted set of the new
process should be transferred to the effective set of the new process.
The effective set is best thought of as a "capability aware" set. It
should consist of only 1s if the executable is capability-dumb, or
only 0s if the executable is capability-smart. Since the effective
set consists of only 0s or only 1s, the filesystem can implement this
set using a single bit.
NOTE: Filesystem support for capabilities is not part of Linux 2.2.
Users and Groups don't have associated capabilities from the kernel's
point of view, but it is entirely reasonable to associate users or
groups with capabilities. By letting the "login" program set some
capabilities it is possible to make role users such as a backup user
that will have the CAP_DAC_READ_SEARCH capability and be able to do
backups. This could also be implemented as a PAM module, but nobody
has implemented one yet.
4) What capabilities exist?
The capabilities available in Linux are listed and documented in the
file /usr/src/linux/include/linux/capability.h.
5) Are Linux capabilities hierarchical?
No, you cannot make a "subcapability" out of a Linux capability as in
capability-based OSes.
6) How can I use capabilities to make sure Mr. Evil Luser (eluser)
can't exploit my "suid" programs?
This is the general outline of how this works given filesystem
capability support exists. First, you have a PAM module that sets the
inheritable capabilities of the login-shell of eluser. Then for all
"suid" programs on the system, you decide what capabilities they need
and set the _allowed_ set of the executable to that set of
capabilities. The capability rules
new permitted = forced | (allowed & inheritable)
means that you should be careful about setting forced capabilities on
executables. In a few cases, this can be useful though. For example
the login program needs to set the inheritable set of the new user and
therefore needs an almost full permitted set. So if you want eluser
to be able to run login and log in as a different user, you will have
to set some forced bits on that executable.
7) What about passing capabilities between processes?
Currently this is done by the system call "setcap" which can set the
capabilities of another process. This requires the CAP_SETPCAP
capability which you really only want to grant a _few_ processes.
CAP_SETPCAP was originally intended as a workaround to be able to
implement filesystem support for capabilities using a daemon outside
the kernel.
There has been discussions about implementing socket-level capability
passing. This means that you can pass a capability over a socket. No
support for this exists in the official kernel yet.
8) I see securelevel has been removed from 2.2 and are superceeded by
capabilities. How do I emulate securelevel using capabilities?
The setcap system call can remove a capability from _all_ processes on
the system in one atomic operation. The setcap utility from the
libcap distribution will do this for you. The utility requires the
CAP_SETPCAP privilege to do this. The CAP_SETPCAP capability is not
enabled by default.
libcap is available from
ftp://ftp.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.2/
9) I noticed that the capability.h file lacks some capabilities that
are needed to fully emulate 2.0 securelevel. Is there a patch for
this?
Actually yes - funny you should ask :-). The problem with 2.0
securelevel is that they for example stop root from accessing block
devices. At the same time they restrict the use of iopl. These two
changes are fundamentally different. Blocking access to block devices
means restricting something that usually isn't restricted.
Restricting access to the use of iopl on the other hand means
restricting (blocking) access to something that is already blocked.
Emulating the parts of 2.0 securelevel that restricts things that are
normally not restricted means that the capabilites in the kernel has
to have a set of capabilities that are usually _on_ for a normal
process (note that this breaks the explanation that capabilities are a
partitioning of the root privileges). There is an experimental patch at
ftp://ftp.guardian.no/pub/free/linux/capabilities/patch-cap-exp-1
which implements a set of capabilities with the "CAP_USER" prefix:
cap_user_sock - allowed to use socket()
cap_user_dev - allowed to open char/block devices
cap_user_fifo - allowed to use pipes
These should be enough to emulate 2.0 securelevel (tell me if we need
something more).
10) Seems I need a CAP_SETPCAP capability that I don't have to make use
of capabilities. How do I enable this capability?
Change the definition of CAP_INIT_EFF_SET and CAP_INIT_INH_SET to the
following in include/linux/capability.h:
#define CAP_INIT_EFF_SET { ~0 }
#define CAP_INIT_INH_SET { ~0 }
This will start init with a full capability set and not with
CAP_SETPCAP removed.
11) How do I start a process with a limited set of capabilities?
Get the libcap library and use the execcap utility. The following
example starts the update daemon with only the CAP_SYS_ADMIN
capability.
execcap 'cap_sys_admin=eip' update
12) How do I start a process with a limited set of capabilities under
another uid?
Use the sucap utility which changes uid from root without loosing any
capabilities. Normally all capabilities are cleared when changing uid
from root. The sucap utility requires the CAP_SETPCAP capability.
The following example starts updated under uid updated and gid updated
with CAP_SYS_ADMIN raised in the Effective set.
sucap updated updated execcap 'cap_sys_admin=eip' update
[ Sucap is currently available from
ftp://ftp.guardian.no/pub/free/linux/capabilities/sucap.c. Put it in
the progs directory of libcap to compile.]
13) What are the "capability rules"
The capability rules are the rules used to set the capabilities of the
new process image after an exec. They work like this:
pI' = pI
(***) pP' = fP | (fI & pI)
pE' = pP' & fE [NB. fE is 0 or ~0]
I=Inheritable, P=Permitted, E=Effective // p=process, f=file
' indicates post-exec().
Now to make sense of the equations think of fP as the Forced set of
the executable, and fI as the Allowed set of the executable. Notice
how the Inheritable set isn't touched at all during exec().
14) What are the laws for setting capability bits in the Inheritable,
Permitted, and Effective sets?
Bits can be transferred from Permitted to either Effective or
Inheritable set.
Bits can be removed from all sets.
15) Where is the standard on which the Linux capabilities are based?
There used to be a POSIX draft called POSIX.6 and later POSIX 1003.1e.
However after the committee had spent over 10 years, POSIX decided
that enough is enough and dropped the draft. There will therefore not
be a POSIX standard covering security anytime soon. This may lead to
that the POSIX draft is available for free, however.
--
Best regards, -- Boris.

6
gating.yaml Normal file
View File

@ -0,0 +1,6 @@
--- !Policy
product_versions:
- rhel-9
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1.functional}

23
getpcaps.8 Normal file
View File

@ -0,0 +1,23 @@
.\" Hey, EMACS: -*- nroff -*-
.TH GETPCAPS 8 "2001-05-29"
.\" Please adjust this date whenever revising the manpage.
.SH NAME
getpcaps \- display process capabilities
.SH SYNOPSIS
.B getpcaps
.IR pid ...
.SH DESCRIPTION
.B getpcaps
displays the capabilities on the processes indicated by the
.I pid
value(s) given on the commandline. The capabilities
are displayed in the
.BR cap_from_text (3)
format.
.SH SEE ALSO
.BR execcap (8).
.br
.SH AUTHOR
This manual page was written by Robert Bihlmeyer <robbe@debian.org>,
for the Debian GNU/Linux system (but may be used by others).

View File

@ -0,0 +1,12 @@
diff --color -ru a/Make.Rules b/Make.Rules
--- a/Make.Rules 2022-01-04 16:57:52.071890314 +0100
+++ b/Make.Rules 2022-01-04 16:59:33.171786150 +0100
@@ -104,7 +104,7 @@
ifeq ($(PTHREADS),yes)
GO ?= go
-GOLANG ?= $(shell if [ -n "$(shell $(GO) version 2>/dev/null)" ]; then echo yes ; else echo no ; fi)
+GOLANG ?= no
ifeq ($(GOLANG),yes)
GOROOT ?= $(shell $(GO) env GOROOT)
GOCGO ?= $(shell if [ "$(shell $(GO) env CGO_ENABLED)" = 1 ]; then echo yes ; else echo no ; fi)

View File

@ -0,0 +1,210 @@
diff --color -ru a/libcap/cap_proc.c b/libcap/cap_proc.c
--- a/libcap/cap_proc.c 2021-02-05 06:52:17.000000000 +0100
+++ b/libcap/cap_proc.c 2021-08-27 10:07:37.627519433 +0200
@@ -689,6 +689,10 @@
cap_value_t c;
int raising = 0;
+ if (temp == NULL) {
+ return -1;
+ }
+
for (i = 0; i < _LIBCAP_CAPABILITY_U32S; i++) {
__u32 newI = iab->i[i];
__u32 oldIP = temp->u[i].flat[CAP_INHERITABLE] |
diff --color -ru a/libcap/cap_text.c b/libcap/cap_text.c
--- a/libcap/cap_text.c 2021-02-05 06:52:17.000000000 +0100
+++ b/libcap/cap_text.c 2021-08-27 10:14:45.180389737 +0200
@@ -160,6 +160,7 @@
cap_blks = _LINUX_CAPABILITY_U32S_3;
break;
default:
+ cap_free(res);
errno = EINVAL;
return NULL;
}
@@ -398,6 +399,9 @@
for (n = 0; n < cmb; n++) {
if (getstateflags(caps, n) == t) {
char *this_cap_name = cap_to_name(n);
+ if (this_cap_name == NULL) {
+ return NULL;
+ }
if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
cap_free(this_cap_name);
errno = ERANGE;
@@ -450,6 +454,9 @@
for (n = cmb; n < __CAP_MAXBITS; n++) {
if (getstateflags(caps, n) == t) {
char *this_cap_name = cap_to_name(n);
+ if (this_cap_name == NULL) {
+ return NULL;
+ }
if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
cap_free(this_cap_name);
errno = ERANGE;
@@ -549,6 +556,9 @@
cap_iab_t cap_iab_from_text(const char *text)
{
cap_iab_t iab = cap_iab_init();
+ if (iab == NULL) {
+ return iab;
+ }
if (text != NULL) {
unsigned flags;
for (flags = 0; *text; text++) {
diff --color -ru a/libcap/_makenames.c b/libcap/_makenames.c
--- a/libcap/_makenames.c 2021-02-05 06:52:17.000000000 +0100
+++ b/libcap/_makenames.c 2021-08-27 10:02:53.263979868 +0200
@@ -49,6 +49,10 @@
int was = pointers_avail * sizeof(char *);
pointers_avail = 2 * list[i].index + 1;
pointers = recalloc(pointers, was, pointers_avail * sizeof(char *));
+ if (pointers == NULL) {
+ perror("unable to continue");
+ exit(1);
+ }
}
pointers[list[i].index] = list[i].name;
int n = strlen(list[i].name);
diff --color -ru a/pam_cap/pam_cap.c b/pam_cap/pam_cap.c
--- a/pam_cap/pam_cap.c 2021-08-26 09:23:55.560021048 +0200
+++ b/pam_cap/pam_cap.c 2021-08-27 10:17:00.406562672 +0200
@@ -60,6 +60,9 @@
}
*groups = calloc(ngrps, sizeof(char *));
+ if (*groups == NULL) {
+ return -1;
+ }
int g_n = 0, i;
for (i = 0; i < ngrps; i++) {
const struct group *g = getgrgid(grps[i]);
diff --color -ru a/progs/capsh.c b/progs/capsh.c
--- a/progs/capsh.c 2021-08-26 09:23:55.561021064 +0200
+++ b/progs/capsh.c 2021-08-27 10:43:32.973136965 +0200
@@ -100,7 +100,16 @@
display_prctl_set("Bounding", cap_get_bound);
display_prctl_set("Ambient", cap_get_ambient);
iab = cap_iab_get_proc();
+ if (iab == NULL) {
+ perror("failed to get IAB for process");
+ exit(1);
+ }
text = cap_iab_to_text(iab);
+ if (text == NULL) {
+ perror("failed to obtain text for IAB");
+ cap_free(iab);
+ exit(1);
+ }
printf("Current IAB: %s\n", text);
cap_free(text);
cap_free(iab);
@@ -402,6 +411,10 @@
child = 0;
char *temp_name = cap_to_name(cap_max_bits() - 1);
+ if (temp_name == NULL) {
+ perror("obtaining highest capability name");
+ exit(1);
+ }
if (temp_name[0] != 'c') {
printf("WARNING: libcap needs an update (cap=%d should have a name).\n",
cap_max_bits() - 1);
diff --color -ru a/progs/getcap.c b/progs/getcap.c
--- a/progs/getcap.c 2021-02-05 06:52:17.000000000 +0100
+++ b/progs/getcap.c 2021-08-27 10:21:36.547999961 +0200
@@ -110,11 +110,11 @@
for (i=optind; argv[i] != NULL; i++) {
struct stat stbuf;
-
- if (lstat(argv[i], &stbuf) != 0) {
- fprintf(stderr, "%s (%s)\n", argv[i], strerror(errno));
+ char *arg = argv[i];
+ if (lstat(arg, &stbuf) != 0) {
+ fprintf(stderr, "%s (%s)\n", arg, strerror(errno));
} else if (recursive) {
- nftw(argv[i], do_getcap, 20, FTW_PHYS);
+ nftw(arg, do_getcap, 20, FTW_PHYS);
} else {
int tflag = S_ISREG(stbuf.st_mode) ? FTW_F :
(S_ISLNK(stbuf.st_mode) ? FTW_SL : FTW_NS);
diff --color -ru a/progs/setcap.c b/progs/setcap.c
--- a/progs/setcap.c 2021-02-05 06:52:17.000000000 +0100
+++ b/progs/setcap.c 2021-08-27 10:23:30.764835298 +0200
@@ -166,9 +166,12 @@
}
cap_on_file = cap_get_file(*++argv);
-
if (cap_on_file == NULL) {
cap_on_file = cap_from_text("=");
+ if (cap_on_file == NULL) {
+ perror("unable to use missing capability");
+ exit(1);
+ }
}
cmp = cap_compare(cap_on_file, cap_d);
diff --color -ru a/psx/psx.c b/psx/psx.c
--- a/psx/psx.c 2021-08-26 09:23:55.562021081 +0200
+++ b/psx/psx.c 2021-08-27 10:24:49.997107969 +0200
@@ -107,6 +107,10 @@
*/
static void *psx_do_registration(void) {
registered_thread_t *node = calloc(1, sizeof(registered_thread_t));
+ if (node == NULL) {
+ perror("unable to register psx handler");
+ exit(1);
+ }
pthread_mutex_init(&node->mu, NULL);
node->thread = pthread_self();
pthread_setspecific(psx_action_key, node);
diff --color -ru a/tests/libcap_launch_test.c b/tests/libcap_launch_test.c
--- a/tests/libcap_launch_test.c 2021-02-05 06:52:17.000000000 +0100
+++ b/tests/libcap_launch_test.c 2021-08-27 10:31:31.662559385 +0200
@@ -93,6 +93,10 @@
printf("[%d] test should %s\n", i,
v->result ? "generate error" : "work");
cap_launch_t attr = cap_new_launcher(v->args[0], v->args, v->envp);
+ if (attr == NULL) {
+ perror("failed to obtain launcher");
+ exit(1);
+ }
if (v->chroot) {
cap_launcher_set_chroot(attr, v->chroot);
}
diff --color -ru a/tests/libcap_psx_test.c b/tests/libcap_psx_test.c
--- a/tests/libcap_psx_test.c 2021-02-05 06:52:17.000000000 +0100
+++ b/tests/libcap_psx_test.c 2021-08-27 10:29:57.157041470 +0200
@@ -16,6 +16,10 @@
usleep(1234);
pid_t pid = fork();
cap_t start = cap_get_proc();
+ if (start == NULL) {
+ perror("FAILED: unable to start");
+ exit(1);
+ }
if (pid == 0) {
cap_set_proc(start);
exit(0);
@@ -27,6 +31,7 @@
exit(1);
}
cap_set_proc(start);
+ cap_free(start);
return NULL;
}
@@ -35,6 +40,10 @@
printf("hello libcap and libpsx ");
fflush(stdout);
cap_t start = cap_get_proc();
+ if (start == NULL) {
+ perror("FAILED: to actually start");
+ exit(1);
+ }
pthread_t ignored[10];
for (i = 0; i < 10; i++) {
pthread_create(&ignored[i], NULL, thread_fork_exit, NULL);

View File

@ -0,0 +1,169 @@
diff --color -ru a/libcap/_makenames.c b/libcap/_makenames.c
--- a/libcap/_makenames.c 2022-01-28 14:41:38.357147972 +0100
+++ b/libcap/_makenames.c 2022-01-28 14:42:45.681379827 +0100
@@ -45,7 +45,7 @@
if (maxcaps <= list[i].index) {
maxcaps = list[i].index + 1;
}
- if (list[i].index >= pointers_avail) {
+ if (pointers == NULL || list[i].index >= pointers_avail) {
int was = pointers_avail * sizeof(char *);
pointers_avail = 2 * list[i].index + 1;
pointers = recalloc(pointers, was, pointers_avail * sizeof(char *));
diff --color -ru a/progs/capsh.c b/progs/capsh.c
--- a/progs/capsh.c 2022-01-28 14:41:38.359148009 +0100
+++ b/progs/capsh.c 2022-01-28 14:42:45.682379846 +0100
@@ -34,6 +34,35 @@
#define MAX_GROUPS 100 /* max number of supplementary groups for user */
+/* parse a non-negative integer with some error handling */
+static unsigned long nonneg_uint(const char *text, const char *prefix, int *ok)
+{
+ char *remains;
+ unsigned long value;
+ ssize_t len = strlen(text);
+
+ if (len == 0 || *text == '-') {
+ goto fail;
+ }
+ value = strtoul(text, &remains, 0);
+ if (*remains) {
+ goto fail;
+ }
+ if (ok != NULL) {
+ *ok = 1;
+ }
+ return value;
+
+fail:
+ if (ok == NULL) {
+ fprintf(stderr, "%s: want non-negative integer, got \"%s\"\n",
+ prefix, text);
+ exit(1);
+ }
+ *ok = 0;
+ return 0;
+}
+
static char *binary(unsigned long value)
{
static char string[8*sizeof(unsigned long) + 1];
@@ -362,7 +391,7 @@
parts = strdup(path);
if (parts == NULL) {
- fprintf(stderr, "insufficient memory for parts of path\n");
+ fprintf(stderr, "insufficient memory for parts of path\n");
exit(1);
}
@@ -610,7 +639,7 @@
unsigned value;
int set;
- value = strtoul(argv[i]+7, NULL, 0);
+ value = nonneg_uint(argv[i]+7, "invalid --keep value", NULL);
set = prctl(PR_SET_KEEPCAPS, value);
if (set < 0) {
fprintf(stderr, "prctl(PR_SET_KEEPCAPS, %u) failed: %s\n",
@@ -667,7 +696,7 @@
} else if (!strncmp("--secbits=", argv[i], 10)) {
unsigned value;
int status;
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --secbits value", NULL);
status = cap_set_secbits(value);
if (status < 0) {
fprintf(stderr, "failed to set securebits to 0%o/0x%x\n",
@@ -680,7 +709,7 @@
fprintf(stderr, "already forked\n");
exit(1);
}
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --forkfor value", NULL);
if (value == 0) {
goto usage;
}
@@ -696,7 +725,8 @@
pid_t result;
unsigned value;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --killit signo value",
+ NULL);
if (!child) {
fprintf(stderr, "no forked process to kill\n");
exit(1);
@@ -722,7 +752,7 @@
unsigned value;
int status;
- value = strtoul(argv[i]+6, NULL, 0);
+ value = nonneg_uint(argv[i]+6, "invalid --uid value", NULL);
status = setuid(value);
if (status < 0) {
fprintf(stderr, "Failed to set uid=%u: %s\n",
@@ -733,7 +763,7 @@
unsigned value;
int status;
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --cap-uid value", NULL);
status = cap_setuid(value);
if (status < 0) {
fprintf(stderr, "Failed to cap_setuid(%u): %s\n",
@@ -744,7 +774,7 @@
unsigned value;
int status;
- value = strtoul(argv[i]+6, NULL, 0);
+ value = nonneg_uint(argv[i]+6, "invalid --gid value", NULL);
status = setgid(value);
if (status < 0) {
fprintf(stderr, "Failed to set gid=%u: %s\n",
@@ -924,7 +954,7 @@
} else if (!strncmp("--is-uid=", argv[i], 9)) {
unsigned value;
uid_t uid;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --is-uid value", NULL);
uid = getuid();
if (uid != value) {
fprintf(stderr, "uid: got=%d, want=%d\n", uid, value);
@@ -933,7 +963,7 @@
} else if (!strncmp("--is-gid=", argv[i], 9)) {
unsigned value;
gid_t gid;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --is-gid value", NULL);
gid = getgid();
if (gid != value) {
fprintf(stderr, "gid: got=%d, want=%d\n", gid, value);
diff --color -ru a/tests/libcap_psx_test.c b/tests/libcap_psx_test.c
--- a/tests/libcap_psx_test.c 2022-01-28 14:41:38.360148027 +0100
+++ b/tests/libcap_psx_test.c 2022-01-28 14:42:45.683379864 +0100
@@ -21,7 +21,10 @@
exit(1);
}
if (pid == 0) {
- cap_set_proc(start);
+ if (cap_set_proc(start)) {
+ perror("setting empty caps failed");
+ exit(1);
+ }
exit(0);
}
int res;
@@ -51,7 +54,10 @@
for (i = 0; i < 10; i++) {
printf("."); /* because of fork, this may print double */
fflush(stdout); /* try to limit the above effect */
- cap_set_proc(start);
+ if (cap_set_proc(start)) {
+ perror("failed to set proc");
+ exit(1);
+ }
usleep(1000);
}
printf(" PASSED\n");

View File

@ -0,0 +1,152 @@
diff --color -ru a/pam_cap/pam_cap.c b/pam_cap/pam_cap.c
--- a/pam_cap/pam_cap.c 2021-02-05 06:52:17.000000000 +0100
+++ b/pam_cap/pam_cap.c 2021-04-23 09:48:00.091122637 +0200
@@ -218,7 +218,7 @@
if (!cap_set_proc(cap_s)) {
ok = 1;
}
- goto cleanup_cap_s;
+ goto cleanup_conf;
}
iab = cap_iab_from_text(conf_caps);
@@ -238,10 +238,9 @@
_pam_drop(conf_caps);
cleanup_cap_s:
- if (cap_s) {
- cap_free(cap_s);
- cap_s = NULL;
- }
+ cap_free(cap_s);
+ cap_s = NULL;
+
return ok;
}
diff --color -ru a/progs/capsh.c b/progs/capsh.c
--- a/progs/capsh.c 2021-02-05 06:52:17.000000000 +0100
+++ b/progs/capsh.c 2021-04-23 09:48:00.095122691 +0200
@@ -336,8 +336,8 @@
*/
static char *find_self(const char *arg0)
{
- int i;
- char *parts, *dir, *scratch;
+ int i, status=1;
+ char *p = NULL, *parts, *dir, *scratch;
const char *path;
for (i = strlen(arg0)-1; i >= 0 && arg0[i] != '/'; i--);
@@ -352,21 +352,45 @@
}
parts = strdup(path);
+ if (parts == NULL) {
+ fprintf(stderr, "insufficient memory for parts of path\n");
+ exit(1);
+ }
+
scratch = malloc(2+strlen(path)+strlen(arg0));
- if (parts == NULL || scratch == NULL) {
+ if (scratch == NULL) {
fprintf(stderr, "insufficient memory for path building\n");
- exit(1);
+ goto free_parts;
}
- for (i=0; (dir = strtok(parts, ":")); parts = NULL) {
+ for (p = parts; (dir = strtok(p, ":")); p = NULL) {
sprintf(scratch, "%s/%s", dir, arg0);
if (access(scratch, X_OK) == 0) {
- return scratch;
+ status = 0;
+ break;
}
}
+ if (status) {
+ fprintf(stderr, "unable to find executable '%s' in PATH\n", arg0);
+ free(scratch);
+ }
+
+free_parts:
+ free(parts);
+ if (status) {
+ exit(status);
+ }
+ return scratch;
+}
- fprintf(stderr, "unable to find executable '%s' in PATH\n", arg0);
- exit(1);
+static long safe_sysconf(int name)
+{
+ long ans = sysconf(name);
+ if (ans <= 0) {
+ fprintf(stderr, "sysconf(%d) returned a non-positive number: %ld\n", name, ans);
+ exit(1);
+ }
+ return ans;
}
int main(int argc, char *argv[], char *envp[])
@@ -617,7 +641,9 @@
* Given we are now in a new directory tree, its good practice
* to start off in a sane location
*/
- status = chdir("/");
+ if (status == 0) {
+ status = chdir("/");
+ }
cap_free(orig);
@@ -718,14 +744,14 @@
gid_t *group_list;
int g_count;
- length = sysconf(_SC_GETGR_R_SIZE_MAX);
+ length = safe_sysconf(_SC_GETGR_R_SIZE_MAX);
buf = calloc(1, length);
if (NULL == buf) {
fprintf(stderr, "No memory for [%s] operation\n", argv[i]);
exit(1);
}
- max_groups = sysconf(_SC_NGROUPS_MAX);
+ max_groups = safe_sysconf(_SC_NGROUPS_MAX);
group_list = calloc(max_groups, sizeof(gid_t));
if (NULL == group_list) {
fprintf(stderr, "No memory for gid list\n");
@@ -741,8 +767,7 @@
}
if (!isdigit(*ptr)) {
struct group *g, grp;
- getgrnam_r(ptr, &grp, buf, length, &g);
- if (NULL == g) {
+ if (getgrnam_r(ptr, &grp, buf, length, &g) || NULL == g) {
fprintf(stderr, "Failed to identify gid for group [%s]\n", ptr);
exit(1);
}
@@ -835,6 +860,7 @@
argv[argc] = NULL;
execve(argv[i], argv+i, envp);
fprintf(stderr, "execve '%s' failed!\n", argv[i]);
+ free(argv[i]);
exit(1);
} else if (!strncmp("--shell=", argv[i], 8)) {
shell = argv[i]+8;
diff --color -ru a/psx/psx.c b/psx/psx.c
--- a/psx/psx.c 2021-02-05 06:52:17.000000000 +0100
+++ b/psx/psx.c 2021-04-23 09:48:00.095122691 +0200
@@ -454,6 +454,10 @@
int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg) {
psx_starter_t *starter = calloc(1, sizeof(psx_starter_t));
+ if (starter == NULL) {
+ perror("failed at thread creation");
+ exit(1);
+ }
starter->fn = start_routine;
starter->arg = arg;
/*

View File

@ -1,7 +1,17 @@
diff --color -ru a/Make.Rules b/Make.Rules
--- a/Make.Rules 2021-02-05 06:52:17.000000000 +0100
+++ b/Make.Rules 2021-12-13 17:09:11.225308225 +0100
@@ -56,10 +56,10 @@
From 7c13fa4e4c044941afd3b3766de71821cdc04397 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 14 Feb 2021 14:06:49 -0800
Subject: [PATCH] Update Make.Rules for Fedora RPM build
---
Make.Rules | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Make.Rules b/Make.Rules
index ded9014..537cb6c 100644
--- a/Make.Rules
+++ b/Make.Rules
@@ -56,10 +56,10 @@ IPATH += -fPIC -I$(KERNEL_HEADERS) -I$(topdir)/libcap/include
CC := $(CROSS_COMPILE)gcc
DEFINES := -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
@ -14,7 +24,7 @@ diff --color -ru a/Make.Rules b/Make.Rules
BUILD_CFLAGS ?= $(BUILD_COPTS) $(DEFINES) $(IPATH)
AR := $(CROSS_COMPILE)ar
RANLIB := $(CROSS_COMPILE)ranlib
@@ -69,7 +69,7 @@
@@ -69,7 +69,7 @@ WARNINGS=-Wall -Wwrite-strings \
-Wstrict-prototypes -Wmissing-prototypes \
-Wnested-externs -Winline -Wshadow
LD=$(CC) -Wl,-x -shared
@ -23,12 +33,5 @@ diff --color -ru a/Make.Rules b/Make.Rules
LIBCAPLIB := -L$(topdir)/libcap -lcap
PSXLINKFLAGS := -lpthread -Wl,-wrap,pthread_create
LIBPSXLIB := -L$(topdir)/libcap -lpsx $(PSXLINKFLAGS)
@@ -104,7 +104,7 @@
ifeq ($(PTHREADS),yes)
GO ?= go
-GOLANG ?= $(shell if [ -n "$(shell $(GO) version 2>/dev/null)" ]; then echo yes ; else echo no ; fi)
+GOLANG ?= no
ifeq ($(GOLANG),yes)
GOROOT ?= $(shell $(GO) env GOROOT)
GOCGO ?= $(shell if [ "$(shell $(GO) env CGO_ENABLED)" = 1 ]; then echo yes ; else echo no ; fi)
--
2.29.2

View File

@ -1,22 +1,21 @@
Name: libcap
Version: 2.48
Release: 6%{?dist}
Release: 9%{?dist}
Summary: Library for getting and setting POSIX.1e capabilities
URL: https://sites.google.com/site/fullycapable/
License: BSD or GPLv2
Group: System Environment/Libraries
Source: https://git.kernel.org/pub/scm/libs/libcap/libcap.git/snapshot/%{name}-%{version}.tar.gz
Patch0: %{name}-2.48-buildflags.patch
Patch1: %{name}-abi-compatibility.patch
Patch2: %{name}-static-analysis.patch
Patch3: %{name}-fix-ambient-caps.patch
Patch4: %{name}-fix-prctl-usage.patch
Patch5: %{name}-check-allocation.patch
Patch6: %{name}-cve-2023-2603.patch
Patch7: %{name}-cve-2023-2602.patch
Patch0: libcap-use-compiler-flag-options.patch
Patch1: libcap-static-analysis-fix.patch
Patch2: libcap-static-analysis-fix-2.patch
Patch3: libcap-static-analysis-fix-3.patch
Patch4: libcap-disable-golang.patch
Patch5: libcap-fix-ambient-caps.patch
Patch6: libcap-cve-2023-2603.patch
Patch7: libcap-cve-2023-2602.patch
BuildRequires: libattr-devel pam-devel perl-interpreter
BuildRequires: libattr-devel pam-devel perl-interpreter gcc
BuildRequires: make
%description
@ -25,7 +24,6 @@ draft 15 capabilities.
%package static
Summary: Static libraries for libcap development
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
%description static
@ -37,7 +35,6 @@ draft 15 capabilities.
%package devel
Summary: Development files for libcap
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
%description devel
@ -72,7 +69,6 @@ chmod +x %{buildroot}/%{_libdir}/*.so.*
%ldconfig_scriptlets
%files
%{!?_licensedir:%global license %%doc}
%license License
%doc doc/capability.notes
%{_libdir}/*.so.*
@ -92,53 +88,81 @@ chmod +x %{buildroot}/%{_libdir}/*.so.*
%{_libdir}/pkgconfig/libcap.pc
%{_libdir}/pkgconfig/libpsx.pc
%changelog
* Wed Dec 13 2023 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 2.48-6
- Bump release version to restore upgrade path
Resolves: RHEL-19362
* Mon Jun 26 2023 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 2.48-5
* Wed Jul 12 2023 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 2.48-9
- Fix integer overflow in _libcap_strdup() (CVE-2023-2603)
Resolves: rhbz#2210637
Resolves: rhbz#2210638
- Correctly check pthread_create() return value to avoid memory leak (CVE-2023-2602)
Resolves: rhbz#2210644
Resolves: rhbz#2222198
* Tue May 17 2022 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 2.48-4
- check for successful memory allocation
related: rhbz#2062648
* Fri Jan 28 2022 Zoltan Fridrich <zfridric@redhat.com> - 2.48-8
- Fix ambient capabilities for non-root users
Related: rhbz#2037215
* Mon May 16 2022 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 2.48-3
- avoid overwriting errno set by prctl
resolves: rhbz#2062648
* Fri Aug 27 2021 Zoltan Fridrich <zfridric@redhat.com> - 2.48-7
- Fix issues detected by static analyzers
Related: rhbz#1985346
* Fri Jan 28 2022 Zoltan Fridrich <zfridric@redhat.com> - 2.48-2
- rebase to 2.48
resolves: rhbz#2032813
- fix ambient capabilities for non-root users
resolves: rhbz#1950187
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.48-6
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Thu Jun 10 2021 Zoltan Fridrich <zfridric@redhat.com> - 2.26-5
- added CAP_PERFMON, CAP_BPF and CAP_CHECKPOINT_RESTORE capabilities
resolves: rhbz#1946982 rhbz#1921576
* Fri Jun 18 2021 Zoltan Fridrich <zfridric@redhat.com> - 2.48-5
- Remove deprecated tests
Resolves: rhbz#1938758
* Fri May 22 2020 Jiri Vymazal <jvymazal@redhat.com> - 2.26-4
- added patch implementing support for ambient capabilities
resolves: rhbz#1487388
* Tue Jun 15 2021 Zoltan Fridrich <zfridric@redhat.com> - 2.48-4
- Fix issues detected by static analyzers (rhbz#1938758)
* Tue Oct 15 2019 Marek Tamaskovic <mtamasko@redhat.com> - 2.26-3
- changed url
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 2.48-3
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Wed May 22 2019 Karsten Hopp <karsten@redhat.com> - 2.26-2
* Sun Feb 14 2021 Peter Robinson <pbrobinson@fedoraproject.org> - 2.48-2
- Rebase distro flags patch
* Wed Feb 10 2021 Giuseppe Scrivano <gscrivan@redhat.com> - 2.48-1
- Update to 0.2.48
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.46-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Sun Jan 17 2021 Peter Robinson <pbrobinson@fedoraproject.org> - 2.46-1
- Update to 0.2.46
* Wed Oct 21 2020 Karsten Hopp <karsten@fedoraproject.org> - 2.44-1
- update to 2.44
- remove additional getpcaps manpage as it now included in the sources
* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.26-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.26-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.26-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Mon Feb 04 2019 Karsten Hopp <karsten@redhat.com> - 2.26-5
- enable gating
* Mon Feb 04 2019 Karsten Hopp <karsten@redhat.com> - 2.26-4
- bump release
* Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.26-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Mon Jan 28 2019 Karsten Hopp <karsten@redhat.com> - 2.26-2
- add CI tests using the standard test interface (astepano)
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.25-12
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Mon Jul 02 2018 Karsten Hopp <karsten@redhat.com> - 2.25-11
- rebuild
* Fri Apr 12 2019 Karsten Hopp <karsten@redhat.com> - 2.26-1
- update to 2.26
* Thu Apr 11 2019 Karsten Hopp <karsten@redhat.com> - 2.25-11
- rebuild
* Thu Apr 11 2019 Karsten Hopp <karsten@redhat.com> - 2.25-10
- rebuild
* Wed Feb 21 2018 Karsten Hopp <karsten@redhat.com> - 2.25-10
- buildrequire gcc
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.25-9
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild

1
sources Normal file
View File

@ -0,0 +1 @@
SHA512 (libcap-2.48.tar.gz) = 90ac6e46531e4893b78b14171537c6dfd06cf617af9e90f38ea0ce4b50161451528aefff41dbe983719e76582cf39f8d7d432f99756e976f62403d5bc3c209c8