-Aufruf%20in%20C%2FC%2B%2B.png)
Derzeit versuche ich, die Möglichkeiten von Linux zu verstehen, indem ich lesehttp://man7.org/linux/man-pages/man7/capabilities.7.html
Ich habe eine kleine C++-Anwendung mit der Fähigkeit erstelltCAP_DAC_READ_SEARCH+eip
Die Funktion funktioniert für die Anwendung einwandfrei. Aber ich habe einen system()
Anruf darin
system("cat /dev/mtdX > targetFile");
Wie kann ich die Berechtigung für diesen Anruf erben?
Bearbeiten:
Ich weiß, dass dies durch + system()
gesteuert wird . In der Dokumentation wird erwähnt, dass der Kindprozess dieselben Rechte erhält wie der Elternprozess. Aber warum wird die Leseberechtigung nicht vererbt?fork()
execl()
fork()
Antwort1
Zunächst einmal sollten Sie system(3)
aus dem Weg gehen; anders als Sie vorschlagen, handelt system(3)
es sich nicht nur um fork+exec
, sondern um etwas recht Komplexes, das das Ändern von Signaldispositionen, das Warten auf das Kind und die Verwendung /bin/sh
als Wrapper (der je nach Laune und Annahmen des Betreuers Fähigkeiten weglassen oder hinzufügen, Umgebungsvariablen, Quellinitialisierungsskripte und andere lustige Dinge durcheinanderbringen kann) beinhaltet. Wenn Sie nur execv*(2)
anstelle von verwenden system(3)
, werden all diese unechten Komplikationen aus dem Weg geräumt.
Zweitens sollten Sie einen genauen Blick auf den execve()
Teil „Transformation der Fähigkeiten während“ werfen.capabilities(7)
Manpage. Ich werde sie hier nicht kopieren und einfügen, aber im Wesentlichen läuft es auf Folgendes hinaus:Fähigkeiten werden NICHT durch execve() vererbt, es sei denn, sie werden hinzugefügt zumUmgebungsSatzdes Threads (Prozesses) und können dort nicht hinzugefügt werden, es sei denn, sie befinden sich bereits im vererbbaren Satz desFaden. (Die "vererbbaren" Fähigkeiten aus den Metadaten der Datei sind nur einMaske, wodurch die des Threads eingeschränkt werden).
Um die durch execve()
Sie geerbten Fähigkeiten zu erhalten, sollten SieA)kopieren Sie sie aus demgestattetzumvererbbarset (was Sie mit demcapset(2)
Systemaufruf [1]) undB)fügen Sie sie hinzu zuUmgebungsset (was Sie tun könnten mitprctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE)
).
Alles zusammen:
$ cat capexec.c
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/capability.h>
#include <err.h>
int main(int ac, char **av){
static char *dav[] = { "/bin/bash", 0 };
struct __user_cap_header_struct hs;
struct __user_cap_data_struct ds[2];
hs.version = 0x20080522; /*_LINUX_CAPABILITY_VERSION_3;*/
hs.pid = getpid();
if(syscall(SYS_capget, &hs, ds)) err(1, "capget");
ds[0].inheritable = ds[0].permitted;
if(syscall(SYS_capset, &hs, ds)) err(1, "capset");
if(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_DAC_READ_SEARCH, 0, 0)) err(1, "prctl(pr_cap_ambient_raise)");
av = ac < 2 ? dav : av + 1;
execvp(*av, av);
err(1, "execvp %s", *av);
}
$ cc -Wall capexec.c -o capexec
# as root
# setcap cap_dac_read_search+ip /tmp/capexec
$ ./capexec dd if=/dev/sda of=/dev/null count=1
1+0 records in
1+0 records out
512 bytes copied, 0.000299173 s, 1.7 MB/s
[1] Die Dokumentation empfiehlt die Verwendung der Bibliothek libcap. Teile dieses Beispiels stammen aus einem Hack, den ich für eine alte Version von Android geschrieben habe, in der es keine libcap gab und viele Header-Definitionen fehlten. Die Konvertierung zur Verwendung der libcap-Wrapper bleibt dem Leser als Übung überlassen.
Antwort2
Danke an @mosvy. Ich habe seine Lösung mit libcap implementiert und sie scheint wie erwartet zu funktionieren.
void inheritCapabilities()
{
cap_t caps;
caps = cap_get_proc();
if (caps == NULL)
throw "Failed to load capabilities";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
cap_value_t cap_list[1];
cap_list[0] = CAP_DAC_READ_SEARCH;
if (cap_set_flag(caps, CAP_INHERITABLE, 1, cap_list, CAP_SET) == -1)
throw "Failed to set inheritable";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
if (cap_set_proc(caps) == -1)
throw "Failed to set proc";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
caps = cap_get_proc();
if (caps == NULL)
throw "Failed to load capabilities";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_DAC_READ_SEARCH, 0, 0) == -1)
throw "Failed to pr_cap_ambient_raise! Error: " + errno;
}
main() {
inheritCapabilities();
char *catargv[5];
catargv[0] = (char *)"cmd";
catargv[1] = (char *)"arg1";
catargv[2] = (char *)"arg2";
catargv[3] = (char *)"arg3";
catargv[4] = NULL;
if (execvp(catargv[0], catargv) == -1)
throw "Failed! command";
}