summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2011-04-25 21:41:09 -0700
committerAndrew G. Morgan <morgan@kernel.org>2011-04-25 21:41:09 -0700
commitf4df8a4ffeaeef271dee296d5fc88eb85827e638 (patch)
treef0571e44ca6d00a4379306c1ac0687ac9f1738e9
parentea806ff7c5a835c0bc607f24f3ac40ef7b39f548 (diff)
downloadlibcap2-f4df8a4ffeaeef271dee296d5fc88eb85827e638.tar.gz
Add some bounding set capability support to libcap.
Include some documentation and a link to capsh's man page. Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r--doc/Makefile3
-rw-r--r--doc/cap_drop_bound.31
-rw-r--r--doc/cap_get_bound.31
-rw-r--r--doc/cap_get_proc.343
-rw-r--r--doc/capsh.111
-rw-r--r--doc/libcap.31
-rw-r--r--libcap/cap_proc.c23
-rw-r--r--libcap/include/sys/capability.h5
-rw-r--r--progs/capsh.c36
9 files changed, 110 insertions, 14 deletions
diff --git a/doc/Makefile b/doc/Makefile
index 5fe2189..7d1f347 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -12,7 +12,8 @@ MAN3S = cap_init.3 cap_free.3 cap_dup.3 \
cap_get_file.3 cap_get_fd.3 cap_set_file.3 cap_set_fd.3 \
cap_copy_ext.3 cap_size.3 cap_copy_int.3 \
cap_from_text.3 cap_to_text.3 cap_from_name.3 cap_to_name.3 \
- capsetp.3 capgetp.3 libcap.3
+ capsetp.3 capgetp.3 libcap.3 \
+ cap_get_bound.3 cap_drop_bound.3
MAN8S = getcap.8 setcap.8
MANS = $(MAN1S) $(MAN3S) $(MAN8S)
diff --git a/doc/cap_drop_bound.3 b/doc/cap_drop_bound.3
new file mode 100644
index 0000000..65ea3e4
--- /dev/null
+++ b/doc/cap_drop_bound.3
@@ -0,0 +1 @@
+.so man3/cap_get_proc.3
diff --git a/doc/cap_get_bound.3 b/doc/cap_get_bound.3
new file mode 100644
index 0000000..65ea3e4
--- /dev/null
+++ b/doc/cap_get_bound.3
@@ -0,0 +1 @@
+.so man3/cap_get_proc.3
diff --git a/doc/cap_get_proc.3 b/doc/cap_get_proc.3
index 18564e5..123ab3d 100644
--- a/doc/cap_get_proc.3
+++ b/doc/cap_get_proc.3
@@ -3,8 +3,8 @@
.\"
.TH CAP_GET_PROC 3 "2008-05-11" "" "Linux Programmer's Manual"
.SH NAME
-cap_get_proc, cap_set_proc, capgetp \- capability manipulation on
-processes
+cap_get_proc, cap_set_proc, capgetp, cap_get_bound, cap_drop_bound \-
+capability manipulation on processes
.SH SYNOPSIS
.B #include <sys/capability.h>
.sp
@@ -12,6 +12,12 @@ processes
.sp
.BI "int cap_set_proc(cap_t " cap_p );
.sp
+.BI "int cap_get_bound(cap_value_t " cap );
+.sp
+.BI "CAP_IS_SUPPORTED(cap_value_t " cap );
+.sp
+.BI "int cap_drop_bound(cap_value_t " cap );
+.sp
.B #include <sys/types.h>
.sp
.BI "cap_t cap_get_pid(pid_t " pid );
@@ -52,6 +58,28 @@ with the process capabilities of the process indicated by
This information can also be obtained from the
.I /proc/<pid>/status
file.
+.PP
+.BR cap_get_bound ()
+with a
+.I cap
+as an argument returns the current value of this bounding set
+capability flag in effect for the current process. This operation is
+unpriveged. Note, a macro function
+.BI "CAP_IS_SUPPORTED(cap_value_t " cap )
+is provided that evaluates to true (1) if the system supports the
+specified capability,
+.IR cap .
+If the system does not support the capability, this function returns
+0. This macro works by testing for an error condition with
+.BR cap_get_bound ().
+.PP
+.BR cap_drop_bound ()
+can be used to lower the specified bounding set capability,
+.BR cap ,
+To complete successfully, the prevailing
+.I effective
+capability set must have a raised
+.BR CAP_SETPCAP .
.SH "RETURN VALUE"
The functions
.BR cap_get_proc ()
@@ -60,7 +88,15 @@ and
return a non-NULL value on success, and NULL on failure.
.PP
The function
+.BR cap_get_bound ()
+returns -1 if the requested capability is unknown, otherwise the
+return value reflects the current state of that capability in the
+prevailing bounding set. Note, a macro function,
+.PP
+The functions
.BR cap_set_proc ()
+and
+.BR cap_drop_bound ()
return zero for success, and \-1 on failure.
.PP
On failure,
@@ -140,6 +176,9 @@ effective capabilities for the caller:
cap_t caps;
cap_value_t cap_list[2];
+ if (!CAP_IS_SUPPORTED(CAP_SETFCAP))
+ /* handle error */
+
caps = cap_get_proc();
if (caps == NULL)
/* handle error */;
diff --git a/doc/capsh.1 b/doc/capsh.1
index 4f9273d..e68df2c 100644
--- a/doc/capsh.1
+++ b/doc/capsh.1
@@ -1,7 +1,7 @@
.\"
.\" capsh.1 Man page added 2009-12-23 Andrew G. Morgan <morgan@kernel.org>
.\"
-.TH CAPSH 1 "2009-12-24" "libcap 2" "User Commands"
+.TH CAPSH 1 "2011-04-24" "libcap 2" "User Commands"
.SH NAME
capsh \- capability shell wrapper
.SH SYNOPSIS
@@ -150,6 +150,15 @@ this effective set is 0x0100. By running:
we observe that the missing capability is:
.BR cap_setpcap .
+.TP
+.BI --supports= xxx
+As the kernel evolves, more capabilities are added. This option can be used
+to verify the existence of a capability on the system. For example,
+.BI --supports= cap_syslog
+will cause capsh to promptly exit with a status of 1 when run on
+kernel 2.6.27. However, when run on kernel 2.6.38 it will silently
+succeed.
+.TP
.SH "EXIT STATUS"
Following successful execution the tool exits with status 0. Following
an error, the tool immediately exits with status 1.
diff --git a/doc/libcap.3 b/doc/libcap.3
index 827ce60..0e76b4e 100644
--- a/doc/libcap.3
+++ b/doc/libcap.3
@@ -111,3 +111,4 @@ and
.BR cap_init (3),
.BR capabilities (7),
.BR getpid (2)
+.BR capsh (1)
diff --git a/libcap/cap_proc.c b/libcap/cap_proc.c
index 7a6af39..6040c02 100644
--- a/libcap/cap_proc.c
+++ b/libcap/cap_proc.c
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 1997-8,2007 Andrew G Morgan <morgan@kernel.org>
+ * Copyright (c) 1997-8,2007,2011 Andrew G Morgan <morgan@kernel.org>
*
- * This file deals with setting capabilities on processes.
+ * This file deals with getting and setting capabilities on processes.
*/
#include "libcap.h"
@@ -103,3 +103,22 @@ int capsetp(pid_t pid, cap_t cap_d)
return error;
}
+/* get a capability from the bounding set */
+
+int cap_get_bound(cap_value_t cap)
+{
+ int result;
+
+ result = prctl(PR_CAPBSET_READ, cap);
+ return result;
+}
+
+/* drop a capability from the bounding set */
+
+int cap_drop_bound(cap_value_t cap)
+{
+ int result;
+
+ result = prctl(PR_CAPBSET_DROP, cap);
+ return result;
+}
diff --git a/libcap/include/sys/capability.h b/libcap/include/sys/capability.h
index c749327..4b54acc 100644
--- a/libcap/include/sys/capability.h
+++ b/libcap/include/sys/capability.h
@@ -93,6 +93,11 @@ extern cap_t cap_get_proc(void);
extern cap_t cap_get_pid(pid_t);
extern int cap_set_proc(cap_t);
+extern int cap_get_bound(cap_value_t);
+extern int cap_drop_bound(cap_value_t);
+
+#define CAP_IS_SUPPORTED(cap) (cap_get_bound(cap) >= 0)
+
/* libcap/cap_extint.c */
extern ssize_t cap_size(cap_t);
extern ssize_t cap_copy_ext(void *, cap_t, ssize_t);
diff --git a/progs/capsh.c b/progs/capsh.c
index b1eb549..4c32279 100644
--- a/progs/capsh.c
+++ b/progs/capsh.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Andrew G. Morgan <morgan@kernel.org>
+ * Copyright (c) 2008-11 Andrew G. Morgan <morgan@kernel.org>
*
* This is a simple 'bash' wrapper program that can be used to
* raise and lower both the bset and pI capabilities before invoking
@@ -80,11 +80,15 @@ int main(int argc, char *argv[], char *envp[])
if (strcmp("all", argv[i]+7) == 0) {
unsigned j = 0;
- while (prctl(PR_CAPBSET_READ, j) >= 0) {
- if (prctl(PR_CAPBSET_DROP, j) != 0) {
+ while (CAP_IS_SUPPORTED(j)) {
+ if (cap_drop_bound(j) != 0) {
+ char *name_ptr;
+
+ name_ptr = cap_to_name(j);
fprintf(stderr,
"Unable to drop bounding capability [%s]\n",
- cap_to_name(j));
+ name_ptr);
+ cap_free(name_ptr);
exit(1);
}
j++;
@@ -445,11 +449,12 @@ int main(int argc, char *argv[], char *envp[])
for (cap=0; (cap < 64) && (value >> cap); ++cap) {
if (value & (1ULL << cap)) {
- const char *ptr;
+ char *ptr;
ptr = cap_to_name(cap);
if (ptr != NULL) {
printf("%s%s", sep, ptr);
+ cap_free(ptr);
} else {
printf("%s%u", sep, cap);
}
@@ -457,6 +462,19 @@ int main(int argc, char *argv[], char *envp[])
}
}
printf("\n");
+ } else if (!memcmp("--supports=", argv[i], 11)) {
+ cap_value_t cap;
+
+ if (cap_from_name(argv[i] + 11, &cap) < 0) {
+ fprintf(stderr, "cap[%s] not recognized by library\n",
+ argv[i] + 11);
+ exit(1);
+ }
+ if (!CAP_IS_SUPPORTED(cap)) {
+ fprintf(stderr, "cap[%s=%d] not supported by kernel\n",
+ argv[i] + 11, cap);
+ exit(1);
+ }
} else if (!strcmp("--print", argv[i])) {
unsigned cap;
int set, status, j;
@@ -476,17 +494,18 @@ int main(int argc, char *argv[], char *envp[])
printf("Bounding set =");
sep = "";
- for (cap=0; (set = prctl(PR_CAPBSET_READ, cap)) >= 0; cap++) {
- const char *ptr;
+ for (cap=0; (set = cap_get_bound(cap)) >= 0; cap++) {
+ char *ptr;
if (!set) {
continue;
}
ptr = cap_to_name(cap);
- if (ptr == 0) {
+ if (ptr == NULL) {
printf("%s%u", sep, cap);
} else {
printf("%s%s", sep, ptr);
+ cap_free(ptr);
}
sep = ",";
}
@@ -542,6 +561,7 @@ int main(int argc, char *argv[], char *envp[])
" --help this message (or try 'man capsh')\n"
" --print display capability relevant state\n"
" --decode=xxx decode a hex string to a list of caps\n"
+ " --supports=xxx exit 1 if capability xxx unsupported\n"
" --drop=xxx remove xxx,.. capabilities from bset\n"
" --caps=xxx set caps as per cap_from_text()\n"
" --inh=xxx set xxx,.. inheritiable set\n"