19 KiB
हीप
हीप की मूल बातें
हीप वह स्थान है जहाँ कोई प्रोग्राम डेटा स्टोर करने के लिए स्टोर कर सकता है जब वह malloc
, calloc
जैसी फ़ंक्शन को कॉल करके डेटा का अनुरोध करता है। इसके अतिरिक्त, जब यह मेमोरी और नहीं चाहिए होती है तो फ़ंक्शन free
को कॉल करके इसे उपलब्ध कर दिया जाता है।
जैसा कि दिखाया गया है, यह बस उसके बाद है जहाँ बाइनरी मेमोरी में लोड हो रहा है (चेक करें [हीप]
खंड):
मूल चंक आवंटन
जब किसी डेटा को हीप में स्टोर करने के लिए अनुरोध किया जाता है, तो उसके लिए हीप का कुछ स्थान आवंटित किया जाता है। यह स्थान एक बिन का होगा और केवल अनुरोधित डेटा + बिन हेडर के स्थान + न्यूनतम बिन आकार ऑफसेट चंक के लिए आरक्षित किया जाएगा। लक्ष्य यह है कि हर चंक को ढूंढना जटिल न करते हुए केवल न्यूनतम मेमोरी को ही आरक्षित करना। इसके लिए, मेटाडेटा चंक जानकारी का उपयोग किया जाता है ताकि पता चल सके कि हर उपयोग किया गया/फ्री चंक कहाँ है।
अनुरोधित मेमोरी एक थ्रेशोल्ड पार करती है, तो mmap
का उपयोग किया जाएगा ताकि अनुरोधित मेमोरी को मैप किया जा सके।
एरीना
मल्टीथ्रेड एप्लिकेशन में, हीप मैनेजर को दुर्घटनाएँ ले जाने वाली रेस कंडीशन से बचना चाहिए। पहले, यह एक ग्लोबल म्यूटेक्स का उपयोग करके किया गया था ताकि केवल एक थ्रेड हीप तक पहुँच सके, लेकिन यह म्यूटेक्स-इंड्यूस्ड बॉटलनेक के कारण प्रदर्शन समस्याएँ उत्पन्न करता था।
इस समस्या का समाधान करने के लिए, ptmalloc2 हीप एलोकेटर ने "एरीना" का परिचय किया, जहाँ प्रत्येक एरीना एक अलग हीप के रूप में काम करता है जिसमें उसके अपने डेटा संरचनाएँ और म्यूटेक्स होते हैं, जो अन्य एरीना का उपयोग करने वाले थ्रेडों को एक-दूसरे के साथ हीप ऑपरेशन करने की अनुमति देते हैं, जब तक वे विभिन्न एरीना का उपयोग न करें।
सबहीप
सबहीप मल्टीथ्रेड एप्लिकेशन में द्वितीय एरीना के लिए मेमोरी आरक्षित करते हैं, जिससे उन्हें मुख्य हीप से अलग रूप से उनके खुद के हीप क्षेत्रों का प्रबंधन करने की अनुमति मिलती है। यहाँ सबहीप मूल हीप से कैसे भिन्न है और वे कैसे काम करते हैं:
- मूल हीप vs. सबहीप:
- मूल हीप सीधे प्रोग्राम के बाइनरी के बाद स्थित है, और यह
sbrk
सिस्टम कॉल का उपयोग करके विस्तारित होता है। - सबहीप, द्वितीय एरीना द्वारा उपयोग किया जाता है,
mmap
के माध्यम से बनाया जाता है, एक सिस्टम कॉल जो एक निर्दिष्ट मेमोरी क्षेत्र को मैप करता है।
mmap
के साथ मेमोरी आरक्षण:
- जब हीप मैनेजर एक सबहीप बनाता है, तो वह
mmap
के माध्यम से एक बड़े ब्लॉक मेमोरी को आरक्षित करता है। यह आरक्षण मेमोरी को तुरंत आवंटित नहीं करता; यह बस एक क्षेत्र निर्धारित करता है जिसका अन्य सिस्टम प्रक्रियाएँ या आवंटन करने वाले उपयोग नहीं कर सकते। - डिफ़ॉल्ट रूप से, सबहीप के लिए आरक्षित आकार 32-बिट प्रक्रियाओं के लिए 1 MB है और 64-बिट प्रक्रियाओं के लिए 64 MB है।
mprotect
के साथ धीरे-धीरे विस्तारण:
- पहले से ही आरक्षित मेमोरी क्षेत्र को
PROT_NONE
के रूप में चिह्नित किया जाता है, जिससे कर्नेल को इस स्थान को अभी तक भौतिक मेमोरी का आवंटन करने की आवश्यकता नहीं होती है। - सबहीप को "बढ़ाने" के लिए, हीप मैनेजर
mprotect
का उपयोग करता है ताकि पृष्ठ अनुमतियों कोPROT_NONE
सेPROT_READ | PROT_WRITE
में बदल सके, कर्नेल को पहले से आरक्षित पतों को भौतिक मेमोरी का आवंटन करने के लिए प्रेरित करते हैं। यह कदम-से-कदम दृष्टिकोण सबहीप को आवश्यकतानुसार विस्तारित करने की अनुमति देता है। - पूरी सबहीप को एक बार खत्म हो जाने पर, हीप मैनेजर एक नई सबहीप बनाता है ताकि आवंटन जारी रह सके।
malloc_state
प्रत्येक हीप (मुख्य एरीना या अन्य थ्रेड एरीना) के पास एक malloc_state
संरचना होती है।
यह महत्वपूर्ण है कि मुख्य एरीना malloc_state
संरचना एक लिब्सी मेमोरी में एक ग्लोबल वेरिएबल है (इसलिए लिब्सी मेमोरी स्थान में स्थित है)।
थ्रेडों के हीप के हीप के malloc_state
संरचना के मामले में, वे अपने थ्रेड "हीप" के अंदर स्थित होते हैं।
इस संरचना से कुछ दिलचस्प बातें नोट करने के लिए हैं (नीचे दिए गए सी कोड देखें):
mchunkptr bins[NBINS * 2 - 2];
में पॉइंटर होते हैं छोटे, बड़े और अनसॉर्टेड बिन्स के पहले और आखिरी चंक्स की ओर (इसलिए -2 क्योंकि इंडेक्स 0 का उपयोग नहीं होता है)- इसलिए, इन बिन्स का पहला चंक इस संरचना के लिए एक पिछले की ओर पॉइंटर होगा और इन बिन्स का आखिरी चंक इस संरचना के लिए एक आगे का पॉइंटर होगा। जिसका मतलब है कि यदि आप मुख्य एरीना में इन पतों को लीक कर सकते हैं तो आपके पास लिब्सी में संरचना के लिए एक पॉइंटर होगा।
- स्ट्रक्ट्स
struct malloc_state *next;
औरstruct malloc_state *next_free;
एरीना के लिंक्ड लिस्ट्स हैं टॉप
चंक आखिरी "चंक" है, जो बस हीप शेष स्थान है। जब टॉप चंक "खाली" हो जाता है, तो हीप पूरी तरह से उपयोग किया जाता है और इसे अधिक स्थान का अनुरोध करना होता है।आखिरी रिमाइंडर
चंक उन मामलों से आता है जहाँ एक सटीक आकार का चंक उपलब्ध नहीं होता है और इसलिए एक बड़ा चंक विभाजित किया जाता है, एक पॉइंटर शेष ह
// From https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_state
struct malloc_state
{
/* Serialize access. */
__libc_lock_define (, mutex);
/* Flags (formerly in max_fast). */
int flags;
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
typedef struct malloc_state *mstate;
malloc_chunk
यह संरचना एक विशेष चंक की यादृच्छिक भागवानी करती है। आवंटित और अप्राप्त चंक्स के लिए विभिन्न फील्ड्स का अलग-अलग मतलब होता है।
// From https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_chunk
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk_nextsize;
};
typedef struct malloc_chunk* mchunkptr;
जैसा पहले टिप्पणी किया गया है, इन टुकड़ों में कुछ मेटाडेटा भी होता है, जो इस छवि में बहुत अच्छी तरह से प्रतिनिधित है:
मेटाडेटा आम तौर पर 0x08B होता है जिससे वर्तमान चंक का आकार दर्शाया जाता है, जिसमें अंतिम 3 बिट इसका दर्शाते हैं:
A
: अगर 1 है तो यह एक सबहीप से आया है, अगर 0 है तो यह मुख्य एरीना में हैM
: अगर 1 है, तो यह चंक mmap के साथ आवंटित किए गए अंतरिक्ष का हिस्सा है और न ही यह हीप का हिस्सा हैP
: अगर 1 है, तो पिछला चंक उपयोग में है
फिर, उपयोगकर्ता डेटा के लिए जगह, और अंत में 0x08B तक पिछले चंक का आकार दर्शाने के लिए जब चंक उपलब्ध होता है (या जब यह आवंटित होता है).
इसके अतिरिक्त, जब उपलब्ध होता है, तो उपयोगकर्ता डेटा में भी कुछ डेटा शामिल होता है:
- अगले चंक के लिए पॉइंटर
- पिछले चंक के लिए पॉइंटर
- सूची में अगले चंक का आकार
- सूची में पिछले चंक का आकार
{% hint style="info" %} ध्यान दें कि इस तरह से सूची को लाइक करने से हर एक चंक को पंजीकृत करने की आवश्यकता नहीं होती है जहां प्रत्येक एकल चंक हो रहा है। {% endhint %}
त्वरित हीप उदाहरण
त्वरित हीप उदाहरण https://guyinatuxedo.github.io/25-heap/index.html लेकिन arm64 में:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(void)
{
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
}
मुख्य कार्यक्रम के अंत में एक ब्रेकपॉइंट सेट करें और देखें कि जानकारी कहां संग्रहित की गई थी:
यह देखने में संभावित है कि स्ट्रिंग पांडा को 0xaaaaaaac12a0
पर संग्रहित किया गया था (जो x0
के अंदर malloc द्वारा प्रतिक्रिया के रूप में दिया गया पता था)। इससे पहले के 0x10 बाइट जांचने पर पता चलता है कि 0x0
यह दिखाता है कि पिछला चंक उपयोग में नहीं है (लंबाई 0) और इस चंक की लंबाई 0x21
है।
अतिरिक्त जगहें आरक्षित की गई हैं (0x21-0x10=0x11) जोड़े गए हेडर्स (0x10) से और 0x1 यह नहीं दिखाता है कि 0x21B आरक्षित किया गया था, बल्कि वर्तमान हेडर की लंबाई के अंतिम 3 बिटों में कुछ विशेष अर्थ हैं। क्योंकि लंबाई हमेशा 16-बाइट एलाइन की जाती है (64-बिट मशीनों में), इन बिट्स का उपयोग वास्तव में कभी भी लंबाई संख्या द्वारा नहीं किया जाएगा।
0x1: Previous in Use - Specifies that the chunk before it in memory is in use
0x2: Is MMAPPED - Specifies that the chunk was obtained with mmap()
0x4: Non Main Arena - Specifies that the chunk was obtained from outside of the main arena
बिन्स और मेमोरी आवंटन/फ्री
जांचें कि बिन्स क्या हैं और वे कैसे संगठित हैं और मेमोरी कैसे आवंटित और फ्री की जाती है:
{% content-ref url="bins-and-memory-allocations.md" %} bins-and-memory-allocations.md {% endcontent-ref %}
हीप फंक्शन सुरक्षा जांच
हीप में शामिल फंक्शन अपने कार्रवाई करने से पहले निश्चित जांच करेंगे ताकि हीप को कोरप्ट नहीं किया गया है:
{% content-ref url="heap-functions-security-checks.md" %} heap-functions-security-checks.md {% endcontent-ref %}