Skip to content

Instantly share code, notes, and snippets.

@sbz
Last active January 26, 2024 14:33
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save sbz/1090868 to your computer and use it in GitHub Desktop.
Save sbz/1090868 to your computer and use it in GitHub Desktop.
example of using linux capabilities interface libcap(3) and dump capabilities flags for the running process
#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;
}
@sbz
Copy link
Author

sbz commented Jul 18, 2011

  • Install libcap-dev package
  • Compile it with:

% 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

@iceberg53
Copy link

Thank you very much
Very helpful

@iceberg53
Copy link

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

@k3a
Copy link

k3a commented Jul 31, 2018

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.

@AndrewGMorgan
Copy link

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.

@sbz
Copy link
Author

sbz commented Jan 28, 2022

@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.

@warsocket
Copy link

warsocket commented May 3, 2022

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");
}```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment