Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2022-2590-analysis — Analisi approfondita di CVE-2022-2590, una variante di Dirty COW nello shmem del kernel Linux, comprendente causa principale, condizione di gara ed exploit proof-of-concept. | Kitploit
Strumenti/GitHubGitHub/moonnull/cve-2022-2590-analysis
Analisi delle VulnerabilitàExploitBinary Exploitation
GitHubmoonnull/cve-2022-2590-analysis

CVE-2022-2590-analysis

Analisi approfondita di CVE-2022-2590, una variante di Dirty COW nello shmem del kernel Linux, comprendente causa principale, condizione di gara ed exploit proof-of-concept.

Vedi Repository
22h 56m faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2022-2590, Dirty COW limitato a shmem

versione del kernel Linux: Linux/x86 6.0.0-rc1 (commit 37887783b3fef877bf34b8992c9199864da4afcb)

Introduzione:

questa vulnerabilità consente all'attaccante di scrivere contenuto arbitrario in una pagina di memoria condivisa di sola lettura, facendo soddisfare i controlli della funzione can_follow_write_pte, che verifica FOLL_FORCE, FOLL_COW e pte_dirty, usando UFFDIO_CONTINUE.

Analisi:

root@kitploit:~
/*
 * FOLL_FORCE can write to even unwritable pte's, but only
 * after we've gone through a COW cycle and they are dirty.
 */
static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
{
	return pte_write(pte) ||
		((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
}

La funzione qui sopra determina se una pte è scrivibile.

La pte è considerata scrivibile se soddisfa una delle seguenti condizioni:

  1. I flag della pte includono il flag di scrittura (writable).
  2. La variabile flags contiene i flag FOLL_FORCE e FOLL_COW, e i flag della pte includono il flag dirty.

Per soddisfare la condizione 2, devono essere impostati i seguenti tre flag:

FOLL_FORCE

root@kitploit:~
static ssize_t mem_rw(struct file *file, char __user *buf,
			size_t count, loff_t *ppos, int write)
{
	...

	flags = FOLL_FORCE | (write ? FOLL_WRITE : 0);

	while (count > 0) {
		size_t this_len = min_t(size_t, count, PAGE_SIZE);

		if (write && copy_from_user(page, buf, this_len)) {
			copied = -EFAULT;
			break;
		}

		this_len = access_remote_vm(mm, addr, page, this_len, flags); // __get_user_pages with FOLL_FORCE on
		if (!this_len) {
			if (!copied)
				copied = -EIO;
			break;
		}

		...
}

La funzione sopra esegue operazioni di lettura/scrittura su /proc/<pid>/mem.

Usando questa funzione, puoi raggiungere la funzione __get_user_pages con il flag FOLL_FORCE attivo.

Sebbene FOLL_FORCE sia pensato per essere usato in ptrace, la sua necessità è stata dimostrata nel commit seguente: https://github.com/torvalds/linux/commit/f511c0b17b081562dca8ac5061dfa86db4c66cc2

  • FOLL_COW

    root@kitploit:~
    /*
    * mmap_lock must be held on entry.  If @locked != NULL and *@flags
    * does not include FOLL_NOWAIT, the mmap_lock may be released.  If it
    * is, *@locked will be set to 0 and -EBUSY returned.
    */
    static int faultin_page(struct vm_area_struct *vma,
    	unsigned long address, unsigned int *flags, bool unshare,
    	int *locked)
    {
      ...
    
      /*
      * The VM_FAULT_WRITE bit tells us that do_wp_page has broken COW when
      * necessary, even if maybe_mkwrite decided not to set pte_write. We
      * can thus safely do subsequent page lookups as if they were reads.
      * But only do so when looping for pte_write is futile: in some cases
      * userspace may also be wanting to write to the gotten user page,
      * which a read fault here might prevent (a readonly page might get
      * reCOWed by userspace write).
      */
      if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
        *flags |= FOLL_COW;
      return 0;
    }
    

    L'operazione OR con FOLL_COW nella funzione faultin_page può essere utilizzata ed è parte della patch per Dirty COW.

    root@kitploit:~
    static long __get_user_pages(struct mm_struct *mm,
     		unsigned long start, unsigned long nr_pages,
     		unsigned int gup_flags, struct page **pages,
     		struct vm_area_struct **vmas, int *locked)
     {
     	...
     retry:
     		/*
     		 * If we have a pending SIGKILL, don't keep faulting pages and
     		 * potentially allocating memory.
     		 */
     		if (fatal_signal_pending(current)) {
     			ret = -EINTR;
     			goto out;
     		}
     		cond_resched();
    
     		page = follow_page_mask(vma, start, foll_flags, &ctx); // can_follow_write_pte
     		if (!page || PTR_ERR(page) == -EMLINK) {
     			ret = faultin_page(vma, start, &foll_flags,
     					   PTR_ERR(page) == -EMLINK, locked); // flags |= FOLL_COW
     			switch (ret) {
     			case 0:
     				goto retry; // try follow page again
     			case -EBUSY:
     			case -EAGAIN:
     				ret = 0;
     				fallthrough;
     			case -EFAULT:
     			case -ENOMEM:
     			case -EHWPOISON:
     				goto out;
     			}
     			BUG();
     		} else if (PTR_ERR(page) == -EEXIST) {
        ...
     }
    

    Per raggiungere la funzione can_follow_write_pte con il flag FOLL_COW attivo, devi chiamare la funzione faultin_page all'interno della funzione __get_user_pages, saltare all'etichetta retry e chiamare di nuovo la funzione faultin_page.

  • pte_dirty

    Questa condizione può essere soddisfatta grazie al commit seguente: https://github.com/torvalds/linux/commit/9ae0f87d009ca6c4aab2882641ddfc319727e3db

    root@kitploit:~
    /*
    * Install PTEs, to map dst_addr (within dst_vma) to page.
    *
    * This function handles both MCOPY_ATOMIC_NORMAL and _CONTINUE for both shmem
    * and anon, and for both shared and private VMAs.
    */
    int mfill_atomic_install_pte(struct mm_struct *dst_mm, pmd_t *dst_pmd,
    		     struct vm_area_struct *dst_vma,
    		     unsigned long dst_addr, struct page *page,
    		     bool newly_allocated, bool wp_copy)
    {
     	...
    
     	_dst_pte = mk_pte(page, dst_vma->vm_page_prot);
     	_dst_pte = pte_mkdirty(_dst_pte); // set pte dirty unconditionally
     	if (page_in_cache && !vm_shared)
     		writable = false;
    
     	...
    }
    

    Grazie alla patch precedente, è possibile installare incondizionatamente una pte per la pagina di memoria condivisa di sola lettura con il flag dirty.

  •  

    Se questi tre flag sono soddisfatti, la funzione can_follow_write_pte restituirà true.

    root@kitploit:~
    static struct page *follow_page_pte(struct vm_area_struct *vma,
    		unsigned long address, pmd_t *pmd, unsigned int flags,
    		struct dev_pagemap **pgmap)
    {
    	...
        
    	// true && !true == false
    	if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
    		pte_unmap_unlock(ptep, ptl);
    		return NULL;
    	}
    
    	page = vm_normal_page(vma, address, pte); // get read-only shared memory page
    
    	...
    
    out:
    	pte_unmap_unlock(ptep, ptl);
    	return page;
    no_page:
    	pte_unmap_unlock(ptep, ptl);
    	if (!pte_none(pte))
    		return NULL;
    	return no_page_table(vma, flags);
    }
    

    La funzione follow_page_pte restituisce la pagina di memoria condivisa di sola lettura.

    Scenario di race condition:

    Quello che segue è lo scenario di race condition dimostrato dal PoC, che verrà introdotto più avanti.

    madvise e readUFFDIO_CONTINUE ioctlpwrite
    madvise // zap the page
    shmem_fault // read fault
    handle_userfault
    userfaultfd_continue
    mcontinue_atomic_pte
    ret = shmem_getpage(inode, pgoff, &page, SGP_NOALLOC); // get page
    mfill_atomic_install_pte
    _dst_pte = pte_mkdirty(_dst_pte); // make pte dirty
    set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte); // install ptemem_rw
    access_remote_vm // with FOLL_FORCE
    __get_user_pages
    can_follow_write_pte // no FOLL_COW, return 0
    faultin_page
    flags
    retry:
    follow_page_pte
    madvise // zap the page
    shmem_fault // read fault
    handle_userfault
    userfaultfd_continue
    mcontinue_atomic_pte
    ret = shmem_getpage(inode, pgoff, &page, SGP_NOALLOC); // get page
    mfill_atomic_install_pte
    _dst_pte = pte_mkdirty(_dst_pte); // make pte dirty
    set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte); // install pte
    can_follow_write_pte // return 1
    copy_to_user(buf, page, this_len) // write content to read-only page

    Le routine madvise e read vengono eseguite due volte; la prima esecuzione induce un retry di __get_user_pages, mentre la seconda porta follow_page_pte a restituire la pagina puntata dalla pte che è stata resa dirty da mfill_atomic_install_pte.

    PoC e patch:

    https://www.openwall.com/lists/oss-security/2022/08/15/1

    Puoi controllare il reproducer di David Hildenbrand al link sopra.

    Tuttavia, poiché il reproducer rende difficile riconoscere l'esatto scenario di race condition, ho modificato il reproducer per favorire un'esecuzione più lineare e, di conseguenza, ho modificato anche il codice sorgente del kernel Linux.

    .config:

    root@kitploit:~
    ...
    CONFIG_USERFAULTFD=y
    CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
    CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
    ...
    

    PoC: (poc.c)

    Patch: (poc_deayzl.patch)

    Per il test, è necessario eseguire i seguenti passi preliminari. (Le istruzioni nel reproducer di david dicono che il percorso del file è /tmp/foo. Ma tmpfs non è memoria condivisa nella versione attuale, quindi la registrazione di userfaultfd fallisce)

    root@kitploit:~
    sudo -s
    echo "asdf" > /dev/shm/foo
    chmod 0404 /dev/shm/foo
    exit
    

    Dopo aver eseguito il PoC, vedrai la seguente schermata.

    PoC-result

    Riferimenti:

    commit: https://github.com/torvalds/linux/commit/5535be3099717646781ce1540cf725965d680e7b

    lore.kernel patch v1: https://lore.kernel.org/linux-mm/[email protected]/#r

    lore.kernel patch v2: https://lore.kernel.org/all/[email protected]/T/#u

    openwall: https://www.openwall.com/lists/oss-security/2022/08/08/1

    openwall2: https://lists.openwall.net/linux-kernel/2022/08/08/418

    Scarica lo strumento