-
-
Save sbz/1090868 to your computer and use it in GitHub Desktop.
#include <sys/capability.h> | |
#include <sys/types.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#define nitems(x) (sizeof(x) / sizeof(x[0])) | |
int | |
main(void) { | |
pid_t pid; | |
cap_t cap; | |
cap_value_t cap_list[CAP_LAST_CAP+1]; | |
cap_flag_t cap_flags; | |
cap_flag_value_t cap_flags_value; | |
// | |
// generated list with command line below: | |
// sed -n 's/^#define \(CAP_.*\) .*/\1/p' /usr/include/linux/capability.h | tr A-Z a-z | |
// don't take cap_last_cap which is the same as the last cap_audit_read capability | |
// | |
const char *cap_name[CAP_LAST_CAP+1] = { | |
"cap_chown", | |
"cap_dac_override", | |
"cap_dac_read_search", | |
"cap_fowner", | |
"cap_fsetid", | |
"cap_kill", | |
"cap_setgid", | |
"cap_setuid", | |
"cap_setpcap", | |
"cap_linux_immutable", | |
"cap_net_bind_service", | |
"cap_net_broadcast", | |
"cap_net_admin", | |
"cap_net_raw", | |
"cap_ipc_lock", | |
"cap_ipc_owner", | |
"cap_sys_module", | |
"cap_sys_rawio", | |
"cap_sys_chroot", | |
"cap_sys_ptrace", | |
"cap_sys_pacct", | |
"cap_sys_admin", | |
"cap_sys_boot", | |
"cap_sys_nice", | |
"cap_sys_resource", | |
"cap_sys_time", | |
"cap_sys_tty_config", | |
"cap_mknod", | |
"cap_lease", | |
"cap_audit_write", | |
"cap_audit_control", | |
"cap_setfcap", | |
"cap_mac_override", | |
"cap_mac_admin", | |
"cap_syslog", | |
"cap_wake_alarm", | |
"cap_block_suspend", | |
"cap_audit_read", | |
}; | |
int i, j; | |
/* temporary use for cap_get_flag calls */ | |
struct { | |
const char *str; | |
cap_flag_t flag; | |
} const flags[3] = { | |
{"EFFECTIVE", CAP_EFFECTIVE}, | |
{"PERMITTED", CAP_PERMITTED}, | |
{"INHERITABLE", CAP_INHERITABLE} | |
}; | |
pid = getpid(); | |
cap = cap_get_pid(pid); | |
if (cap == NULL) { | |
perror("cap_get_pid"); | |
exit(-1); | |
} | |
/* set effective cap */ | |
cap_list[0] = CAP_CHOWN; | |
if (cap_set_flag(cap, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1) { | |
perror("cap_set_flag cap_chown"); | |
cap_free(cap); | |
exit(-1); | |
} | |
/* set permitted cap */ | |
cap_list[0] = CAP_MAC_ADMIN; | |
if (cap_set_flag(cap, CAP_PERMITTED, 1, cap_list, CAP_SET) == -1) { | |
perror("cap_set_flag cap_mac_admin"); | |
cap_free(cap); | |
exit(-1); | |
} | |
/* set inherit cap */ | |
cap_list[0] = CAP_SETFCAP; | |
if (cap_set_flag(cap, CAP_INHERITABLE, 1, cap_list, CAP_SET) == -1) { | |
perror("cap_set_flag cap_setfcap"); | |
cap_free(cap); | |
exit(-1); | |
} | |
/* dump them */ | |
for (i=0; i < cap_max_bits(); i++) { | |
cap_from_name(cap_name[i], &cap_list[i]); | |
printf("%-20s %d\t\t", cap_to_name(cap_list[i]), cap_list[i]); | |
printf("flags: \t\t"); | |
for (j=0; j < nitems(flags); j++) { | |
cap_get_flag(cap, cap_list[i], flags[j].flag, &cap_flags_value); | |
printf(" %s %-4s ", flags[j].str, (cap_flags_value == CAP_SET) ? "OK" : "NOK"); | |
} | |
printf("\n"); | |
} | |
cap_free(cap); | |
return 0; | |
} |
Thank you very much
Very helpful
For compiling, I had to use gcc lcap.c -lcap -g -o lcap
instead of the command you provided due to some undefined reference error to [libcap function]
according to this stackoverflow answer
I also encountered a segmentation fault (core dumped)
that I'm trying to fix ...
I'm using ubuntu 16.04 with the corresponding repository libcap-dev package.
Once again thank you
Sigsegv because new capabilities were added and you are initializing remaining names with NULL values:
Update start of the for block
for (i=0; i < CAP_LAST_CAP + 1; i++) {
if (!cap_name[i]) {
break;
}
"continue" could be used but as they are not empty spots in the array "break" makes more sense.
FWIW There is a function called cap_to_name()
in libcap
that pretty much does what you are doing with cap_name[i]
. Also, libcap
provides the function cap_max_bits()
which returns the number of capabilities known to the running kernel which doesn't require you rely having access to the kernel header for your running kernel to build.
@AndrewGMorgan Thanks, it's great to have a feedback from the original author of libcap. I wrote this gist 11 years ago so it definitely need an update I guess.
From a quick look cap_to_name() is existing for a long time and cap_max_bits() seems to have been added last year with release 2.30 apparently.
If you remove the cap_name array and replace the final loop with the following It would work as @AndrewGMorgan stated:
int i;
char* cap_name;
for (i=0; i < CAP_LAST_CAP + 1; i++) {
cap_name = cap_to_name(i);
cap_from_name(cap_name, &cap_list[i]);
printf("%-20s %d\t\t", cap_name, cap_list[i]);
cap_free(cap_name);
printf("flags: \t\t");
cap_get_flag(cap, cap_list[i], CAP_EFFECTIVE, &cap_flags_value);
printf(" EFFECTIVE %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
cap_get_flag(cap, cap_list[i], CAP_PERMITTED, &cap_flags_value);
printf(" PERMITTED %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
cap_get_flag(cap, cap_list[i], CAP_INHERITABLE, &cap_flags_value);
printf(" INHERITABLE %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
printf("\n");
}```
% make lcap CFLAGS+="-lcap -g"
cc -lcap -g lcap.c -o lcap
% ./lcap
cap_chown 0 flags: EFFECTIVE OK PERMITTED NOK INHERITABLE NOK
...
cap_syslog 34 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK