리눅스/커널2014. 4. 7. 19:22

arch/arm/mm/init.c : mem_init(void)


 586        unsigned long reserved_pages, free_pages;
 587        struct memblock_region *reg;
 /*
 633         * Since our memory may not be contiguous, calculate the
 634         * real number of pages we have in this system
 635         */
 636        printk(KERN_INFO "Memory:");
 637        num_physpages = 0;
 638        for_each_memblock(memory, reg) {
 639                unsigned long pages = memblock_region_memory_end_pfn(reg) -
 640                        memblock_region_memory_base_pfn(reg);
 641                num_physpages += pages;
 642                printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
 643        }
 644        printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
 645
 646        printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
 647                nr_free_pages() << (PAGE_SHIFT-10),
 648                free_pages << (PAGE_SHIFT-10),
 649                reserved_pages << (PAGE_SHIFT-10),
 650                totalhigh_pages << (PAGE_SHIFT-10));

include/linux/memblock.h

 150#define for_each_memblock(memblock_type, region)                                        \
 151        for (region = memblock.memblock_type.regions;                           \
 152             region < (memblock.memblock_type.regions + memblock.memblock_type.cnt);    \
 153             region++)
 154

include/linux/memblock.h

 123/**
 124 * memblock_region_memory_end_pfn - Return the end_pfn this region
 125 * @reg: memblock_region structure
 126 */
 127static inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg)
 128{
 129        return PFN_DOWN(reg->base + reg->size);
 130}

include/linux/memblock.h

 132/**
 133 * memblock_region_reserved_base_pfn - Return the lowest pfn intersecting with the reserved region
 134 * @reg: memblock_region structure
 135 */
 136static inline unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg)
 137{
 138        return PFN_DOWN(reg->base);
 139}


include/linux/memblock.h

  37struct memblock {
  38        phys_addr_t current_limit;
  39        phys_addr_t memory_size;        /* Updated by memblock_analyze() */
  40        struct memblock_type memory;
  41        struct memblock_type reserved;
  42};

meminfo 라는 구조체에 nr_banks 와 membank라는 구조체가 멤버로 있다.  이들은 부팅 과정에서 이미 arm_add_memory라는 함수를 통해서 bank에 대한 start 및 size가 정해졌있다.(
early_init_dt_add_memory()나 parse_tag_mem32()등의 함수를 통해서 세팅된다(확인필요)

  29struct membank {
  30        phys_addr_t start;
  31        phys_addr_t size;
  32        unsigned int highmem;
  33};
  34
  35struct meminfo {
  36        int nr_banks;
  37        struct membank bank[NR_BANKS];
  38};

그리고 arch/arm/mm/init.c:find_limits()라는 함수를 통해서, 각 메모리 뱅크를 돌면서 (참고로 이건 3.1.10소스다. 최신은 좀 틀리다)

 135static void __init find_limits(unsigned long *min, unsigned long *max_low,
 136        unsigned long *max_high)
 137{
 138        struct meminfo *mi = &meminfo;
 139        int i;
 140
 141        *min = -1UL;
 142        *max_low = *max_high = 0;
 143
 144        for_each_bank (i, mi) {
 145                struct membank *bank = &mi->bank[i];
 146                unsigned long start, end;
 147
 148                start = bank_pfn_start(bank);
 149                end = bank_pfn_end(bank);
 150
 151                if (*min > start)
 152                        *min = start;
 153                if (*max_high < end)
 154                        *max_high = end;
 155                if (bank->highmem)
 156                        continue;
 157                if (*max_low < end)
 158                        *max_low = end;
 159        }
 160}

밑의 매크로를 통해서 페이지프레임넘버를 가져온다.  

  45#define bank_pfn_start(bank)    __phys_to_pfn((bank)->start)
  46#define bank_pfn_end(bank)      __phys_to_pfn((bank)->start + (bank)->size)
 139#define __phys_to_pfn(paddr)    ((unsigned long)((paddr) >> PAGE_SHIFT))

가져온 pfn을 start, end에 assign하고 전달받은 min, max_low, max_high를 그에 맞게 설정해 준다.  

그 후, bootmem_init()에서 arm_bootmem_init(min, max_low)를 통해 bootmem bitmap page 할당, bootmem allocator 초기화, lowmem 해재, lowmem memblock reservation 등을 한다.

위의 할당된 bootmem 은 나중에 init/main.c 에서 mem_init()를 호출하면,

 453static void __init mm_init(void)
 454{
 455        /*
 456         * page_cgroup requires countinous pages as memmap
 457         * and it's bigger than MAX_ORDER unless SPARSEMEM.
 458         */
 459        page_cgroup_init_flatmem();
 460        mem_init();
 461        kmem_cache_init();
 462        percpu_init_late();
 463        pgtable_cache_init();
 464        vmalloc_init();
 465}

mem_init()에서 bootmem에 할당되었던 메모리를 해제한다.
 600 totalram_pages += free_all_bootmem();

mm/bootmem.c

 250unsigned long __init free_all_bootmem(void)
 251{
 252        unsigned long total_pages = 0;
 253        bootmem_data_t *bdata;
 254
 255        list_for_each_entry(bdata, &bdata_list, list)
 256                total_pages += free_all_bootmem_core(bdata);
 257
 258        return total_pages;
 259}

자 그러면 이제 우리가 원하던 부분이다.

 610        reserved_pages = free_pages = 0;
 611
 612        for_each_bank(i, &meminfo) {
 613                struct membank *bank = &meminfo.bank[i];
 614                unsigned int pfn1, pfn2;
 615                struct page *page, *end;
 616
 617                pfn1 = bank_pfn_start(bank);
 618                pfn2 = bank_pfn_end(bank);
 619
 620                page = pfn_to_page(pfn1);
 621                end  = pfn_to_page(pfn2 - 1) + 1;
 622
 623                do {
 624                        if (PageReserved(page))
 625                                reserved_pages++;
 626                        else if (!page_count(page))
 627                                free_pages++;
 628                        page++;
 629                } while (page < end);
 630        }
 631
 632        /*
 633         * Since our memory may not be contiguous, calculate the
 634         * real number of pages we have in this system
 635         */
 636        printk(KERN_INFO "Memory:");
 637        num_physpages = 0;
 638        for_each_memblock(memory, reg) {
 639                unsigned long pages = memblock_region_memory_end_pfn(reg) -
 640                        memblock_region_memory_base_pfn(reg);
 641                num_physpages += pages;
 642                printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
 643        }
 644        printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
 645
 646        printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
 647                nr_free_pages() << (PAGE_SHIFT-10),
 648                free_pages << (PAGE_SHIFT-10),
 649                reserved_pages << (PAGE_SHIFT-10),
 650                totalhigh_pages << (PAGE_SHIFT-10));
 651
 652#define MLK(b, t) b, t, ((t) - (b)) >> 10
 653#define MLM(b, t) b, t, ((t) - (b)) >> 20
 654#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
 655
 656        printk(KERN_NOTICE "Virtual kernel memory layout:\n"
 657                        "    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 658#ifdef CONFIG_HAVE_TCM
 659                        "    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 660                        "    ITCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 661#endif
 662                        "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 663#ifdef CONFIG_MMU
 664                        "    DMA     : 0x%08lx - 0x%08lx   (%4ld MB)\n"
 665#endif
 666                        "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
 667                        "    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"
 668#ifdef CONFIG_HIGHMEM
 669                        "    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
 670#endif
 671                        "    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
 672                        "      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
 673                        "      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
 674                        "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
 675                        "       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",

meminfo의 nr_bank숫자 만큼 루핑을 하면서, bank의 start주소와 end주소의 pfn을 가져와, 각각 page, end에 저장시키고, page에서부터 end까지 안에서 루핑하면서, page가 reserved일 경우, reserved_pages++ 하고, !page_count(page)일 경우 free_pages++하고, 마지막으로 page를 increment시킨다.

 for_each_memblock(memory, reg) 는 
 150#define for_each_memblock(memblock_type, region)                                        \
 151        for (region = memblock.memblock_type.regions;                           \
 152             region < (memblock.memblock_type.regions + memblock.memblock_type.cnt);    \
 153             region++)

memblock_type의 memory안의 memblock_region의 regions을 돌면서(memory의 cnt숫자만큼), 

  26struct memblock_region {
  27        phys_addr_t base;
  28        phys_addr_t size;
  29};
  30
  31struct memblock_type {
  32        unsigned long cnt;      /* number of regions */
  33        unsigned long max;      /* size of the allocated array */
  34        struct memblock_region *regions;
  35};
  36
  37struct memblock {
  38        phys_addr_t current_limit;
  39        phys_addr_t memory_size;        /* Updated by memblock_analyze() */
  40        struct memblock_type memory;
  41        struct memblock_type reserved;
  42};

pages에 region의 base + size의 PFN 값에서 base의 PFN값을 뺀 값을 설정한다.

 639                unsigned long pages = memblock_region_memory_end_pfn(reg) -
 640                        memblock_region_memory_base_pfn(reg);

그리고 이렇게 얻어진 pages를 num_phypages에 증가시켜준다.

그러면 드디오 이 num_phypages >> (20 - PAGE_SHIFT)가
Memory: = xxx MB total

에 나오는 xxx가 된다. 

'리눅스 > 커널' 카테고리의 다른 글

syslog LOCAL7  (0) 2014.08.28
Dentry cache hash table 사이즈  (0) 2014.04.08
driver 초기화 시에 쓰이는 module_init  (0) 2014.04.04
Machine 이름 바꾸기  (0) 2014.04.03
Machine 이름 알아내기  (0) 2014.04.03
Posted by code cat
리눅스/커널2014. 4. 4. 09:13

driver초기화 시에 흔히 불리는 module_init(x)는 include/linux/init.h에

#define module_init(x)    __initcall(x);

로 정의되어 있다.  여기서 x는 kernel 부팅 타임이나 모듈 삽입시에 불리는 함수명이 된다.

built in 모듈일 경우, do_initcalls()에서 불릴 것이고,

module 일 경우, module insertion에 불린다.

'리눅스 > 커널' 카테고리의 다른 글

Dentry cache hash table 사이즈  (0) 2014.04.08
Memory 정보 출력되는 곳  (0) 2014.04.07
Machine 이름 바꾸기  (0) 2014.04.03
Machine 이름 알아내기  (0) 2014.04.03
early_param에 대해  (0) 2014.03.31
Posted by code cat
리눅스/커널2014. 4. 3. 13:39

MACH_TYPE_XXX 와 machine 이름을 overwrite하기 위해서는 아래 매크로를 활용하면 된다.

linux/arch/arm/include/asm/mach/arch.h

  79 * Set of macros to define architecture features.  This is built into
  80 * a table by the linker.
  81 */
  82#define MACHINE_START(_type,_name)                      \
  83static const struct machine_desc __mach_desc_##_type    \
  84 __used                                                 \
  85 __attribute__((__section__(".arch.info.init"))) = {    \
  86        .nr             = MACH_TYPE_##_type,            \
  87        .name           = _name,
  88
  89#define MACHINE_END                             \
  90};


'리눅스 > 커널' 카테고리의 다른 글

Memory 정보 출력되는 곳  (0) 2014.04.07
driver 초기화 시에 쓰이는 module_init  (0) 2014.04.04
Machine 이름 알아내기  (0) 2014.04.03
early_param에 대해  (0) 2014.03.31
/dev/tty 와 /dev/console의 차이점  (0) 2014.02.05
Posted by code cat
리눅스/커널2014. 4. 3. 09:30

start_kernel()-->setup_arch()-->setup_machine_tags()

arch/arm/kernel/setup.c에서setup_arch()함수 내에서 머신이름을 설정한다.

machine_arch_type은 include/generated/mach-types.h에서 정의되어 있는데 이는 gen-mach-types 툴을 이용해서 생성된다.
예)
define MACH_TYPE_CODECAT             1

ifdef CONFIG_CODECAT
define machine_arch_type                   MACH_TYPE_CODECAT

machine_arch_type은 setup_machine_tags의 인자로 넘어가고, setup_machine_tags()내의
for_each_machine_desc는 __arch_info_begin 에서 __arch_info_end 를 순환하면서 machine_desc구조체의 nr(architecture number를 인자로 받아온 machine_arch_type과 비교하여 같은 경우, archiecture name을 찍어준다.

'리눅스 > 커널' 카테고리의 다른 글

driver 초기화 시에 쓰이는 module_init  (0) 2014.04.04
Machine 이름 바꾸기  (0) 2014.04.03
early_param에 대해  (0) 2014.03.31
/dev/tty 와 /dev/console의 차이점  (0) 2014.02.05
FrameBuffer size 구하기  (0) 2013.12.11
Posted by code cat
안드로이드/포팅2014. 4. 1. 09:38

출처: Nathaniel Husted, Augst 19, 2011, "Notes regarding Android OS System Development and Security as of Android 2.3.4"


7 Android Escalation of Privledge Attacks

Two attacks against the Android platform currently exist. These attacks

allow a user-level privledge to gain root privledges on the Android platform.

They both exploit userland vulnerabilities in Android. Some of these exploits

have been fixed, but the fixes depend on the manufacturer10

.

7.1 Rage Against The Cage

The Rage Against The Cage exploit takes advantage of a bug in the adb

code. The adb code on android performs certain actions as root at start up

but then drops root privledges using setuid. The exploit is in that the adb

code does not check if the setuid call succeeds of fails. If the call fails adb will

continue to run as the root user. Rage Against The Cage works by forking

enough children processes to reach the NPROC limit on the machine and

attempts to restart adb while NPROC is maxed. When this happens, the

setuid call will fail in adb and it will continue to run with root privledges.

Details can be found at http://intrepidusgroup.com/insight/2010/

09/android-root-source-code-looking-at-the-c-skills/.


7.2 Exploid

The exploid vulnerability takes advantage of the udev system on Android.

The Google developers removed a large amount of code from udev as it would

be implemented on Linux and moved the code into the init daemon. The

dillema is that the udev code used is susceptible to a bug that existed in

udev prior to 1.4.1 that did not verif that kernel messages it received came

from the kernel. In the Android OS this means that init would receive these

requests and init runs as root. A brief overview of the exploit is as follows:

1. Exploid copies it to a system directory writable to the shell user

2. It then sends a “NETLINK_KOBJECT_UEVENT” message to the

kernel.

3. Copied executable checks to see if it srunning as root..

4. When running as root, remounts system partition as read-write

5. Finally copies /system/bin/sh to /system/bin/rootshell and chmod’s

to 04711 to always run as root.

Details can be found at http://intrepidusgroup.com/insight/2010/

09/android-root-source-code-looking-at-the-c-skills/.


7.3 KillingInTheNameOf

The KillingInTheNameOf exploit is slightly different in that it takes advantage

of google’s custom shmem interface “ashmem”. The program maps the

system properties into a processes adress space. The vulnerability is that

they are not maped as write protected. The vulnerability then finds the

ro.secure property of adb and flips it. That allows any shell started by adb

to run as root. Rough details can be found in http://jon.oberheide.org/

files/bsides11-dontrootrobots.pdf.


7.4 ZimperLich

The ZimperLich follows the same structure as the Exploid vulnerability.

There are two major differences, though. First, ZimperLich attacks the

Zygote process on android and its lack of a check against the failure of setuid.

The Zygote process is the parent process which all Dalvik jails are

forked from. the other difference is that attacking Zygote does not require

a shell with a uid so the ZimperLich attack can be run from an APK. The

source code for ZimperLich can be found at http://c-skills.blogspot.

com/2011/02/zimperlich-sources.html.


7.5 GingerBreak

The GingerBreak exploit works in a similar manner to the Exploid vulnerability.

The difference is that in this case the exploit takes advantage of the

“vold” daemon improperly trusting messages recieved. A buffer underflow attack

is commited that causes and escalation of privledge attack. The attack

was found to work on on a number of devices from Android 2.2 to Android

3.0. The vulnerability is CVE-2011-1823. The very general description can be

found at https://groups.google.com/group/android-security-discuss/

browse\_thread/thread/1ac1582b7307fc5c. Source code for the exploit

can be found at http://c-skills.blogspot.com/2011/04/yummy-yummy-gingerbreak.

html.

This has supposedly been fixed in newer versions of the Android source

11 as of May 2nd.

Posted by code cat