aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2023-06-24 22:23:31 -0700
committerAndrew G. Morgan <morgan@kernel.org>2023-06-24 22:24:00 -0700
commitac8d461a2ce1ca3ea68099d75b5e6fd09f48fcef (patch)
treec8bcee2ad7e9f64954aa3844279ea9543ad2dba1
parent8785077d6c69482a2814a2f771aaada2f6ea1894 (diff)
downloadlibcap-ac8d461a2ce1ca3ea68099d75b5e6fd09f48fcef.tar.gz
Make it harder to set invalid capabilities on files.
This change introduces the setcap -f argument to allow setting of nonsense capabilities on files. But the default is to fail when attempting to set such invalid capabilities. This commit addresses: https://bugzilla.kernel.org/show_bug.cgi?id=217592 Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r--doc/getcap.824
-rw-r--r--doc/setcap.88
-rw-r--r--progs/setcap.c33
3 files changed, 55 insertions, 10 deletions
diff --git a/doc/getcap.8 b/doc/getcap.8
index 8b6d201..65214b3 100644
--- a/doc/getcap.8
+++ b/doc/getcap.8
@@ -22,6 +22,30 @@ enables recursive search.
.TP 4
.B \-v
display all searched entries, even if the have no file-capabilities.
+.PP
+NOTE: an
+.I empty
+value of
+.B '='
+is
+.B not
+equivalent to an omitted (or removed) capability on a
+file. This is most significant with respect to the Ambient capability
+vector, since a process with Ambient capabilities will lose them when
+executing a file having
+.B '='
+capabilities, but will retain the Ambient inheritance of privilege
+when executing a file with an omitted file capability. This special
+.I empty
+setting can be used to prevent a binary from executing with
+privilege. For some time, the kernel honored this suppression for root
+executing the file, but the kernel developers decided after a number
+of years that this behavior was unexpected for the superuser and
+reverted it just for that user identity. Suppression of root
+privilege, for a process tree, is possible, using the
+.BR capsh (1)
+.B \-\-mode
+option.
.TP 4
.IR filename
One file per line.
diff --git a/doc/setcap.8 b/doc/setcap.8
index d652076..c6b1d50 100644
--- a/doc/setcap.8
+++ b/doc/setcap.8
@@ -44,6 +44,14 @@ ambient+inheritable sets would otherwise bestow capabilities on
executed binaries.
.PP
The
+.BR '\-f' ,
+is used to force completion even when it is in some way considered
+an invalid operation. This can affect
+.B '\-r'
+and setting file capabilities the kernel will not be able to make
+sense of.
+.PP
+The
.B \-q
flag is used to make the program less verbose in its output.
.SH "EXIT CODE"
diff --git a/progs/setcap.c b/progs/setcap.c
index 737efcc..598272c 100644
--- a/progs/setcap.c
+++ b/progs/setcap.c
@@ -24,6 +24,7 @@ static void usage(int status)
" [ Note: capsh --suggest=\"something...\" might help you pick. ]"
"\n"
" -h this message and exit status 0\n"
+ " -f force setting even when the capability is invalid\n"
" -q quietly\n"
" -v validate supplied capability matches file\n"
" -n <rootid> write a user namespace (!= 0) limited capability\n"
@@ -99,7 +100,7 @@ int main(int argc, char **argv)
{
int tried_to_cap_setfcap = 0;
char buffer[MAXCAP+1];
- int retval, quiet = 0, verify = 0;
+ int retval, quiet = 0, verify = 0, forced = 0;
cap_t mycaps;
cap_value_t capflag;
uid_t rootid = 0, f_rootid;
@@ -132,6 +133,10 @@ int main(int argc, char **argv)
" <morgan@kernel.org>\n", argv[0]);
exit(0);
}
+ if (!strcmp(*argv, "-f")) {
+ forced = 1;
+ continue;
+ }
if (!strcmp(*argv, "-h")) {
usage(0);
}
@@ -245,12 +250,11 @@ int main(int argc, char **argv)
}
tried_to_cap_setfcap = 1;
}
- retval = cap_set_file(*++argv, cap_d);
- if (retval != 0) {
+#ifdef linux
+ {
+ // Linux's file capabilities have a compressed representation.
int explained = 0;
- int oerrno = errno;
int somebits = 0;
-#ifdef linux
cap_value_t cap;
cap_flag_value_t per_state;
@@ -269,12 +273,18 @@ int main(int argc, char **argv)
}
}
if (somebits && explained) {
- fprintf(stderr, "NOTE: Under Linux, effective file capabilities must either be empty, or\n"
- " exactly match the union of selected permitted and inheritable bits.\n");
+ fprintf(stderr, "Error: under Linux, effective file capabilities must either be empty, or\n"
+ " exactly match the union of selected permitted and inheritable bits.\n");
+ if (!forced) {
+ exit(1);
+ }
}
+ }
#endif /* def linux */
-
- switch (oerrno) {
+ errno = 0;
+ retval = cap_set_file(*++argv, cap_d);
+ if (retval != 0) {
+ switch (errno) {
case EINVAL:
fprintf(stderr,
"Invalid file '%s' for capability operation\n",
@@ -285,13 +295,16 @@ int main(int argc, char **argv)
fprintf(stderr,
"File '%s' has no capablity to remove\n",
argv[0]);
+ if (forced) {
+ break;
+ }
exit(1);
}
/* FALLTHROUGH */
default:
fprintf(stderr,
"Failed to set capabilities on file '%s': %s\n",
- argv[0], strerror(oerrno));
+ argv[0], strerror(errno));
exit(1);
}
}