2016-09-13 3 views
0

Ich habe Probleme zu verstehen, warum mein Setuid-Programm scheint nicht wie es tatsächlich erhöht Berechtigungen ist, obwohl die ID scheint richtig. Dies läuft auf einem Kernel 2.6 und schlägt fehl, funktioniert aber genauso wie unter Ubuntu 14.04, was dasselbe tut. Ich brauche ein Programm, das zu bestimmten Zeiten während der Ausführung erhöhte Berechtigungen benötigt, während die geringste Berechtigung der Standard ist.setuid Programm funktioniert nicht auf Kernel 2.6

#include <stdio.h> 
#include <stdint.h> 
#include <arpa/inet.h> 
#include <stdint.h> 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 

static uid_t _orig_euid; 

void save_privilege(void){ 
    _orig_euid = geteuid(); 
    printf("saved privilege: %d\n", _orig_euid); 
} 

void drop_privileges(void){ 
    if(seteuid(getuid()) == -1){ 
     exit(0); 
    } 
    printf("dropped privileges %d %d\n", getuid(), geteuid()); 
} 

void reacquire_privileges(void){ 
    if(setuid(_orig_euid) == -1){ 
     exit(0); 
    } 
    printf("reacquired privileges %d %d\n", getuid(), geteuid()); 
} 

void do_privileged(int rw){ 
    switch(rw){ 
     case 0: 
      //read from driver 
      system("dd if=/dev/myrandom bs=10 count=1"); 
     case 1: 
      //write to driver 
      system("dd if=/dev/zero of=/dev/myrandom"); 
     case 2: 
      //change something in proc fs 
      system("echo 3 > /proc/sys/vm/drop_caches"); 
     default: 
      break; 
    } 
} 

int main(int argc, char *argv[]){ 
    int i; 

    if(argc != 2){ 
     printf("usage: %s testno\n", argv[0]); 
     return 0; 
    } 

    i = atoi(argv[1]); 

    save_privilege(); 

    do_privileged(i); 

    drop_privileges(); 

    do_privileged(i); 

    reacquire_privileges(); 

    do_privileged(i); 

    return 0; 
} 

Mein Programm Berechtigungen wie festgelegt sind:

ls -l 
-rwsr-xr-x 1 root  root   6547 Sep 13 00:35 test 

id Mein aktueller Benutzer ist:

id 
uid=1000(user) gid=1000(user) 

Der procfs Eintrag zu schreiben ich versuche:

ls -l /proc/sys/vm/drop_caches 
-rw-r--r-- 1 root  root   0 Sep 13 00:36 /proc/sys/vm/drop_caches 

Wenn ich das Programm ausführen, bekomme ich:

./test 2 
saved privilege: 0 
sh: cannot create /proc/sys/vm/drop_caches: Permission denied 
dropped privileges 1000 1000 
sh: cannot create /proc/sys/vm/drop_caches: Permission denied 
reacquired privileges 1000 0 
sh: cannot create /proc/sys/vm/drop_caches: Permission denied 

Allerdings läuft das gleiche Programm auf Ubuntu 14.04 richtig - es ist nur fehlgeschlagen, den procfs-Eintrag zu ändern, wenn Privilegien fallen gelassen werden.

Hier ist ein strace (./test_perm ist das gleiche wie ./test).

$ strace ./test_perm 2 
execve("./test_perm", ["./test_perm", "2"], [/* 8 vars */]) = 0 
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40005000 
open("/lib/libc.so.0", O_RDONLY)  = 3 
fstat(3, {st_mode=S_IFREG|0755, st_size=310348, ...}) = 0 
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40006000 
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\260\256\0\0004\0\0\0"..., 4096) = 4096 
mmap2(NULL, 360448, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4000e000 
mmap2(0x4000e000, 303968, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x4000e000 
mmap2(0x40060000, 4972, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x4a) = 0x40060000 
mmap2(0x40062000, 15112, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40062000 
close(3)        = 0 
munmap(0x40006000, 4096)    = 0 
stat("/lib/ld-uClibc.so.0", {st_mode=S_IFREG|0755, st_size=21200, ...}) = 0 
mprotect(0x40060000, 4096, PROT_READ) = 0 
mprotect(0x4000c000, 4096, PROT_READ) = 0 
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0 
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0 
geteuid32()        = 1000 
write(1, "saved privilege: 1000\n", 22saved privilege: 1000 
) = 22 
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_DFL, [], 0}, 8) = 0 
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_DFL, [], 0}, 8) = 0 
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [], 0}, 8) = 0 
vfork(sh: cannot create /proc/sys/vm/drop_caches: Permission denied 
)         = 1183 
--- SIGCHLD (Child exited) @ 0 (0) --- 
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0 
wait4(1183, [{WIFEXITED(s) && WEXITSTATUS(s) == 2}], 0, NULL) = 1183 
rt_sigaction(SIGQUIT, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGINT, {SIG_DFL, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0 
getuid32()        = 1000 
setresuid32(-1, 1000, -1)    = 0 
getuid32()        = 1000 
geteuid32()        = 1000 
write(1, "dropped privileges 1000 1000\n", 29dropped privileges 1000 1000 
) = 29 
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_DFL, [INT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0 
vfork(sh: cannot create /proc/sys/vm/drop_caches: Permission denied 
)         = 1184 
--- SIGCHLD (Child exited) @ 0 (0) --- 
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0 
wait4(1184, [{WIFEXITED(s) && WEXITSTATUS(s) == 2}], 0, NULL) = 1184 
rt_sigaction(SIGQUIT, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGINT, {SIG_DFL, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0 
setuid32(1000)       = 0 
getuid32()        = 1000 
geteuid32()        = 1000 
write(1, "reacquired privileges 1000 1000\n", 32reacquired privileges 1000 1000 
) = 32 
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_DFL, [INT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0 
vfork(sh: cannot create /proc/sys/vm/drop_caches: Permission denied 
)         = 1185 
--- SIGCHLD (Child exited) @ 0 (0) --- 
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0 
wait4(1185, [{WIFEXITED(s) && WEXITSTATUS(s) == 2}], 0, NULL) = 1185 
rt_sigaction(SIGQUIT, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGINT, {SIG_DFL, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0 
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0 
exit(0)         = ? 
+0

Was ist die nächste Nummer in Version 2.6? Im Gegensatz zu 3.x und 4.x Kernel-Serie, hat es einen Sinn. In jedem Fall ist 2.6.x Kernel-Serie relativ alt, willst du es wirklich unterstützen? Auch das Kompilieren eines alten Kerns unter einer modernen Distribution kann eine Unmöglichkeit zwischen Kernel-Kern und libc einführen. Können Sie die gleiche Operation ('echo 3>/proc/sys/vm/drop_caches') ohne Ihr Programm ausführen (mit' su' oder 'sudo/bin/sh -c ')? – Tsyvarev

+0

@Tsyvarev, sogar * y * macht Sinn in * 2.6.x.y * Versionierung. – 0andriy

+0

Es ist möglich, dass die Ausgabeumleitung '>' Probleme mit der Funktion system() verursacht. Ist das "Echo 3> ..." der einzige Befehl, der nicht funktioniert? Ist dies der Fall, versuchen Sie, in den privilegierten Modus zu wechseln, indem Sie die proc-Datei tatsächlich über open (2) öffnen und auf diese schreiben (2). – kaiwan

Antwort

0

Wenn Sie Ihr Programm unter strace aufrufen, wird das Bit setuid ignoriert.

Sie haben versucht, setuid-Binärdateien mit ruid == aufzurufen, die die ID des Benutzers aufrufen. Das funktioniert nicht sehr gut. aber das scheint auch nicht das Hauptproblem zu sein.

Do not jemals Anruf System() von einem Setuid-Programm sonst jemand tut SHELL=/tmp/evil your_setuid_program und hat Root zum Frühstück.

Ich zögere sogar herauszufinden, was Sie hier wirklich falsch machen, was dazu führt, dass das setuid-Bit für Sie nicht funktioniert, weil Sie offensichtlich keine Ahnung haben, wie man setuid-Binärdateien schreibt.

+0

Nun, ich habe eine Anwendung in Embedded Linux, die in der Lage sein muss, System() -Aufrufe durchzuführen, aber Berechtigungen zu reduzieren, wenn System() -Aufrufe nicht benötigt werden, alles, was ich gelesen habe, macht es zu einem Setuid-Programm, sofort reduzieren Privilegien Zu Beginn der Anwendung, dann require Root-Berechtigungen nur bei Bedarf (wenn ich System() -Aufrufe machen muss), und dann wieder Berechtigungen löschen, haben Sie einen besseren Vorschlag, wie dies zu tun? –

+0

@wireless_freedom: Versuchen Sie, ein Programm zu schreiben, das als root läuft und genau das tut, was es tun muss, ohne system() aufzurufen und dann können wir reden. Wenn du das nicht kannst, dann hat das keinen Sinn. Für alle Ihre Beispiele außer insmod sollten Sie überhaupt keine Programme starten. – Joshua

Verwandte Themen