From 43bb8fc47ab91c9d23b989e6e647d293ea4bdfb8 Mon Sep 17 00:00:00 2001 From: navidpadid Date: Thu, 22 Jan 2026 00:08:55 +0000 Subject: [PATCH 1/7] added the heap section --- README.md | 28 ++++++++++++++++++++++------ scripts/quick-reference.sh | 18 +++++++++++++++++- src/elf_det.c | 12 ++++++++---- src/elf_det_tests.c | 16 +++++++++++++++- src/elf_helpers.h | 15 +++++++++++++++ 5 files changed, 77 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index cdf7c34..887d928 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ This project implements a Linux Kernel Module that provides access to process in - **Process ID (PID)** and **Process Name** - **CPU Usage** statistics -- **Memory Layout**: Code, Data, and BSS sections +- **Memory Layout**: Code, Data, BSS, and Heap sections - **ELF Binary** information -- **Start/End addresses** for code and data segments +- **Start/End addresses** for code, data, BSS, and heap segments The project consists of two main components: 1. **Kernel Module** (`elf_det.c`) - Runs in kernel space and gathers process information @@ -25,6 +25,7 @@ The project consists of two main components: - **Process Memory Inspection**: View detailed memory layout of any running process - **CPU Usage Tracking**: Real-time CPU usage percentage calculation - **ELF Section Analysis**: Extract ELF binary sections (code, data, BSS) +- **Heap Analysis**: Track heap start and end addresses for dynamic memory allocation - **Proc Filesystem Interface**: Easy interaction through `/proc/elf_det/` - **Sequential File Operations**: Efficient data reading using kernel seq_file API - **User-Friendly CLI**: Simple command-line interface for querying process information @@ -139,8 +140,8 @@ ps aux | grep ************enter the process id: 1234 the process info is here: -PID NAME CPU START_CODE END_CODE START_DATA END_DATA BSS_START BSS_END ELF -01234 bash 0.5 0x0000563a1234 0x0000563a5678 0x0000563a9abc 0x0000563adef0 0x00007ffc1234 0x00007ffc5678 0x0000000000000040 +PID NAME CPU(%) START_CODE END_CODE START_DATA END_DATA BSS_START BSS_END HEAP_START HEAP_END ELF +01234 bash 0.50 0x0000563a1234 0x0000563a5678 0x0000563a9abc 0x0000563adef0 0x00007ffc1234 0x00007ffc5678 0x0000563b0000 0x0000563b8000 0x0000000000000040 ``` ### 4. Uninstall the Module @@ -217,6 +218,13 @@ The kernel module creates entries in `/proc/elf_det/`: - `procfile_write()` - Handles PID input from user space - `procfile_read()` - Returns formatted process data +**Memory Information Extracted:** +- **Code Section**: `start_code` to `end_code` - executable code region +- **Data Section**: `start_data` to `end_data` - initialized data region +- **BSS Section**: `end_data` to `start_brk` - uninitialized data region +- **Heap Section**: `start_brk` to `brk` - dynamic memory allocation region +- **ELF Header**: Location of the ELF binary header + **Kernel APIs Used:** - `proc_fs.h` - Proc filesystem operations - `seq_file.h` - Sequential file interface @@ -241,7 +249,7 @@ Internally, path construction is handled via helper `build_proc_path()`. Helper headers used: - `src/user_helpers.h` – path building with env override -- `src/elf_helpers.h` – pure functions for CPU usage and BSS range +- `src/elf_helpers.h` – pure functions for CPU usage, BSS range, and heap range ## Code Quality and Static Analysis @@ -357,7 +365,7 @@ make unit ``` This builds and runs: -- `src/elf_det_tests.c` – verifies `compute_usage_permyriad()` and `compute_bss_range()` +- `src/elf_det_tests.c` – verifies `compute_usage_permyriad()`, `compute_bss_range()`, and `compute_heap_range()` - `src/proc_elf_ctrl_tests.c` – verifies `build_proc_path()` with and without `ELF_DET_PROC_DIR` Artifacts are created under `build/`. @@ -570,6 +578,14 @@ Contributions, issues, and feature requests are welcome! ## Changelog +### Version 1.2 +- Added heap start and end address extraction +- Enhanced memory layout analysis with heap region tracking +- Added `compute_heap_range()` helper function +- Updated unit tests to cover heap range computation +- Improved documentation with comprehensive heap information +- Updated output format to include HEAP_START and HEAP_END columns + ### Version 1.1 - Integrated static analysis tools (clang-format, sparse, cppcheck, checkpatch) - Automated Git pre-commit hooks for code quality diff --git a/scripts/quick-reference.sh b/scripts/quick-reference.sh index 6df98d0..f76e13a 100755 --- a/scripts/quick-reference.sh +++ b/scripts/quick-reference.sh @@ -107,11 +107,27 @@ PROJECT STRUCTURE src/proc_elf_ctrl.c - User program source src/elf_det_tests.c - Unit tests for elf_det src/proc_elf_ctrl_tests.c - Unit tests for proc_elf_ctrl - src/elf_helpers.h - Helper functions (CPU, BSS) + src/elf_helpers.h - Helper functions (CPU, BSS, heap) src/user_helpers.h - Helper functions (path building) build/ - Compiled artifacts +MEMORY INFORMATION EXTRACTED +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + PID - Process ID + NAME - Process name + CPU(%) - CPU usage percentage + START_CODE - Start of executable code section + END_CODE - End of executable code section + START_DATA - Start of initialized data section + END_DATA - End of initialized data section + BSS_START - Start of uninitialized data section + BSS_END - End of uninitialized data section + HEAP_START - Start of heap (dynamic memory) + HEAP_END - Current end of heap (brk) + ELF - ELF header location + + TIPS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - Always run 'make unit' first (no kernel required) diff --git a/src/elf_det.c b/src/elf_det.c index 82cfb01..55eb949 100644 --- a/src/elf_det.c +++ b/src/elf_det.c @@ -38,6 +38,7 @@ static int elfdet_show(struct seq_file *m, void *v) { struct task_struct *task; unsigned long bss_start = 0, bss_end = 0; + unsigned long heap_start = 0, heap_end = 0; unsigned long elf_header = 0; u64 delta_ns, total_ns; u64 usage_permyriad; // CPU usage in hundredths of a percent (X.XX%) @@ -69,23 +70,26 @@ static int elfdet_show(struct seq_file *m, void *v) return 0; } - /* Use mm fields directly for ELF and BSS */ + /* Use mm fields directly for ELF, BSS, and heap */ elf_header = task->mm->start_code; compute_bss_range(task->mm->end_data, task->mm->start_brk, &bss_start, &bss_end); + compute_heap_range(task->mm->start_brk, task->mm->brk, &heap_start, + &heap_end); mmap_read_unlock(task->mm); // now print the information we want to the det file seq_puts(m, "PID \tNAME \tCPU(%) \tSTART_CODE \tEND_CODE " - "\tSTART_DATA\tEND_DATA \tBSS_START\tBSS_END\tELF\n"); + "\tSTART_DATA\tEND_DATA " + "\tBSS_START\tBSS_END\tHEAP_START\tHEAP_END\tELF\n"); seq_printf(m, "%.5d\t%.7s\t%llu.%02llu\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%." - "13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\n", + "13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\n", task->pid, task->comm, (usage_permyriad / 100), (usage_permyriad % 100), task->mm->start_code, task->mm->end_code, task->mm->start_data, task->mm->end_data, - bss_start, bss_end, elf_header); + bss_start, bss_end, heap_start, heap_end, elf_header); return 0; } diff --git a/src/elf_det_tests.c b/src/elf_det_tests.c index 575b86f..8f22231 100644 --- a/src/elf_det_tests.c +++ b/src/elf_det_tests.c @@ -14,7 +14,7 @@ int main(void) /* compute_bss_range tests */ unsigned long s = 0, e = 0; - int ret1, ret2; + int ret1, ret2, ret3, ret4; ret1 = compute_bss_range(1000UL, 2000UL, &s, &e); assert(ret1 == 1); @@ -24,6 +24,20 @@ int main(void) assert(ret2 == 0); assert(s == 0UL && e == 0UL); + /* compute_heap_range tests */ + ret3 = compute_heap_range(5000UL, 8000UL, &s, &e); + assert(ret3 == 1); + assert(s == 5000UL && e == 8000UL); + + ret4 = compute_heap_range(9000UL, 7000UL, &s, &e); + assert(ret4 == 0); + assert(s == 0UL && e == 0UL); + + /* Test heap with same start and end (empty heap) */ + ret1 = compute_heap_range(10000UL, 10000UL, &s, &e); + assert(ret1 == 1); + assert(s == 10000UL && e == 10000UL); + puts("elf_helpers tests passed"); return 0; } diff --git a/src/elf_helpers.h b/src/elf_helpers.h index ac65bfa..48d4777 100644 --- a/src/elf_helpers.h +++ b/src/elf_helpers.h @@ -32,3 +32,18 @@ static inline int compute_bss_range(unsigned long end_data, *out_end = start_brk; return 1; } + +/* Compute heap range from start_brk and brk; returns 0 on invalid */ +static inline int compute_heap_range(unsigned long start_brk, unsigned long brk, + unsigned long *out_start, + unsigned long *out_end) +{ + if (brk < start_brk) { + *out_start = 0; + *out_end = 0; + return 0; + } + *out_start = start_brk; + *out_end = brk; + return 1; +} From ee129cdbb52fdcea29152227ba5aefa7541ef4c6 Mon Sep 17 00:00:00 2001 From: navidpadid Date: Thu, 22 Jan 2026 00:24:55 +0000 Subject: [PATCH 2/7] stack end and elf base fixed --- README.md | 50 +++++++++++++++++++++++++----- scripts/quick-reference.sh | 22 ++++++++++---- src/elf_det.c | 62 ++++++++++++++++++++++++++++++-------- src/elf_helpers.h | 15 +++++++-- 4 files changed, 120 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 887d928..7d9800a 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ This project implements a Linux Kernel Module that provides access to process in - **Process ID (PID)** and **Process Name** - **CPU Usage** statistics -- **Memory Layout**: Code, Data, BSS, and Heap sections +- **Memory Layout**: Code, Data, BSS, Heap, and Stack sections - **ELF Binary** information -- **Start/End addresses** for code, data, BSS, and heap segments +- **Start/End addresses** for code, data, BSS, heap, and stack segments The project consists of two main components: 1. **Kernel Module** (`elf_det.c`) - Runs in kernel space and gathers process information @@ -25,7 +25,8 @@ The project consists of two main components: - **Process Memory Inspection**: View detailed memory layout of any running process - **CPU Usage Tracking**: Real-time CPU usage percentage calculation - **ELF Section Analysis**: Extract ELF binary sections (code, data, BSS) -- **Heap Analysis**: Track heap start and end addresses for dynamic memory allocation +- **Heap Analysis**: Track heap start and end addresses for dynamic memory allocation (brk-based) +- **Stack Tracking**: Monitor stack start address - **Proc Filesystem Interface**: Easy interaction through `/proc/elf_det/` - **Sequential File Operations**: Efficient data reading using kernel seq_file API - **User-Friendly CLI**: Simple command-line interface for querying process information @@ -140,10 +141,12 @@ ps aux | grep ************enter the process id: 1234 the process info is here: -PID NAME CPU(%) START_CODE END_CODE START_DATA END_DATA BSS_START BSS_END HEAP_START HEAP_END ELF -01234 bash 0.50 0x0000563a1234 0x0000563a5678 0x0000563a9abc 0x0000563adef0 0x00007ffc1234 0x00007ffc5678 0x0000563b0000 0x0000563b8000 0x0000000000000040 +PID NAME CPU(%) START_CODE END_CODE START_DATA END_DATA BSS_START BSS_END HEAP_START HEAP_END STACK_START STACK_END ELF_BASE +01234 bash 0.50 0x0000563a1234 0x0000563a5678 0x0000563a9abc 0x0000563adef0 0x0000563adef0 0x0000563adef0 0x0000563b0000 0x0000563b8000 0x00007ffd12345000 0x00007ffd12340000 0x0000563a1000 ``` +**Note**: BSS_START and BSS_END may be equal (zero-length BSS) in modern ELF binaries. This is normal. + ### 4. Uninstall the Module ```bash @@ -219,11 +222,26 @@ The kernel module creates entries in `/proc/elf_det/`: - `procfile_read()` - Returns formatted process data **Memory Information Extracted:** -- **Code Section**: `start_code` to `end_code` - executable code region +- **Code Section**: `start_code` to `end_code` - executable code region (includes rodata) - **Data Section**: `start_data` to `end_data` - initialized data region - **BSS Section**: `end_data` to `start_brk` - uninitialized data region -- **Heap Section**: `start_brk` to `brk` - dynamic memory allocation region -- **ELF Header**: Location of the ELF binary header +- **Heap Section**: `start_brk` to `brk` - brk-based dynamic memory allocation +- **Stack**: `start_stack` (top/base) to `stack_end` (current lower bound) +- **ELF Base**: Base address of the ELF binary (first VMA, typically lower than start_code for PIE) + +**Important Notes and Limitations:** + +1. **BSS May Be Zero-Length**: Modern ELF binaries often have `end_data == start_brk`, resulting in zero-length BSS. This is normal, not an error. + +2. **Read-Only Data (rodata)**: The read-only data segment is typically merged with the code section (`start_code` to `end_code`) in modern binaries. It's not shown separately. + +3. **Heap Limitation**: The heap shown is **brk-based only** (traditional heap managed by brk/sbrk syscalls). Modern allocators like glibc's malloc also use: + - **mmap-based allocations** for large requests (>128KB typically) + - **Arena heaps** (multiple heap regions) + - These are NOT included in the brk-based heap range shown + - To see full heap usage, parse `/proc/pid/maps` for anonymous `[heap]` entries and unnamed mmap regions + +4. **Stack**: Shows both `start_stack` (top/base) and `stack_end` (current lower boundary). The stack grows downward from start_stack. The actual current stack pointer (in CPU registers) may be anywhere between these bounds. **Kernel APIs Used:** - `proc_fs.h` - Proc filesystem operations @@ -578,6 +596,22 @@ Contributions, issues, and feature requests are welcome! ## Changelog +### Version 1.3 +- Added `STACK_END` extraction by parsing stack VMA +- Fixed `ELF` column to show actual ELF base address (renamed to `ELF_BASE`) +- Clarified that ELF_BASE is the first VMA (PIE binary base) +- Stack now shows full range (start to end) +- Improved VMA iteration for stack boundary detection + +### Version 1.2.1 +- Added stack start address extraction (`STACK_START` column) +- Improved documentation of memory layout limitations +- Added comprehensive notes about BSS zero-length in modern binaries +- Documented brk-based heap limitation (mmap heaps not tracked) +- Clarified that rodata is merged with code section +- Enhanced code comments for better understanding +- Fixed potential confusion about "always zero" BSS + ### Version 1.2 - Added heap start and end address extraction - Enhanced memory layout analysis with heap region tracking diff --git a/scripts/quick-reference.sh b/scripts/quick-reference.sh index f76e13a..f33c273 100755 --- a/scripts/quick-reference.sh +++ b/scripts/quick-reference.sh @@ -117,15 +117,25 @@ MEMORY INFORMATION EXTRACTED PID - Process ID NAME - Process name CPU(%) - CPU usage percentage - START_CODE - Start of executable code section + START_CODE - Start of executable code section (includes rodata) END_CODE - End of executable code section START_DATA - Start of initialized data section END_DATA - End of initialized data section - BSS_START - Start of uninitialized data section - BSS_END - End of uninitialized data section - HEAP_START - Start of heap (dynamic memory) - HEAP_END - Current end of heap (brk) - ELF - ELF header location + BSS_START - Start of uninitialized data (may equal BSS_END) + BSS_END - End of uninitialized data + HEAP_START - Start of brk-based heap (see limitations below) + HEAP_END - Current end of brk-based heap + STACK_START - Top of stack (highest address, grows downward) + STACK_END - Current bottom of stack (lower boundary) + ELF_BASE - Base address of ELF binary (first VMA, for PIE) + +IMPORTANT LIMITATIONS +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + • BSS may be zero-length (BSS_START == BSS_END) in modern binaries + • rodata segment merged with code section (not shown separately) + • Heap shows only brk-based allocations (not mmap-based arenas) + • Modern malloc uses mmap for large allocations (not tracked here) + • Stack shows only start address (grows downward from there) TIPS diff --git a/src/elf_det.c b/src/elf_det.c index 55eb949..9302a64 100644 --- a/src/elf_det.c +++ b/src/elf_det.c @@ -39,9 +39,12 @@ static int elfdet_show(struct seq_file *m, void *v) struct task_struct *task; unsigned long bss_start = 0, bss_end = 0; unsigned long heap_start = 0, heap_end = 0; - unsigned long elf_header = 0; + unsigned long stack_start = 0, stack_end = 0; + unsigned long elf_base = 0; u64 delta_ns, total_ns; u64 usage_permyriad; // CPU usage in hundredths of a percent (X.XX%) + struct vm_area_struct *vma; + struct ma_state mas; int ret; ret = kstrtoint(buff, 10, &user_pid); @@ -70,26 +73,59 @@ static int elfdet_show(struct seq_file *m, void *v) return 0; } - /* Use mm fields directly for ELF, BSS, and heap */ - elf_header = task->mm->start_code; + /* Use mm fields directly for ELF, BSS, heap, and stack + * Note: Modern ELF binaries may have end_data == start_brk (no BSS) + * rodata is typically merged with code section (start_code to end_code) + * Heap shown is brk-based; mmap-allocated heap is not tracked here + */ + + /* ELF base: First VMA is typically the ELF binary base (for PIE) */ + mas_init(&mas, &task->mm->mm_mt, 0); + vma = mas_find(&mas, ULONG_MAX); + if (vma) + elf_base = vma->vm_start; + + /* Stack: Find the [stack] VMA for actual stack boundaries */ + stack_start = task->mm->start_stack; + mas_set(&mas, 0); + mas_for_each(&mas, vma, ULONG_MAX) + { + if (vma->vm_start <= task->mm->start_stack && + vma->vm_end >= task->mm->start_stack) { + /* Found the stack VMA */ + stack_end = vma->vm_start; /* Stack grows down */ + break; + } + } + + /* BSS: uninitialized data between end_data and start_brk + * May be zero-length in modern binaries + */ compute_bss_range(task->mm->end_data, task->mm->start_brk, &bss_start, &bss_end); + + /* Heap: brk-based heap from start_brk to current brk + * Note: Does not include mmap-based allocations (arena heap) + */ compute_heap_range(task->mm->start_brk, task->mm->brk, &heap_start, &heap_end); mmap_read_unlock(task->mm); // now print the information we want to the det file - seq_puts(m, "PID \tNAME \tCPU(%) \tSTART_CODE \tEND_CODE " - "\tSTART_DATA\tEND_DATA " - "\tBSS_START\tBSS_END\tHEAP_START\tHEAP_END\tELF\n"); - seq_printf(m, - "%.5d\t%.7s\t%llu.%02llu\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%." - "13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\n", - task->pid, task->comm, (usage_permyriad / 100), - (usage_permyriad % 100), task->mm->start_code, - task->mm->end_code, task->mm->start_data, task->mm->end_data, - bss_start, bss_end, heap_start, heap_end, elf_header); + seq_puts( + m, "PID \tNAME \tCPU(%) \tSTART_CODE \tEND_CODE " + "\tSTART_DATA\tEND_DATA \tBSS_START\tBSS_END\tHEAP_START\tHEAP_" + "END\tSTACK_START\tSTACK_END\tELF_BASE\n"); + seq_printf( + m, + "%.5d\t%.7s\t%llu.%02llu\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%." + "13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%.13lx\t0x%." + "13lx\t0x%.13lx\n", + task->pid, task->comm, (usage_permyriad / 100), + (usage_permyriad % 100), task->mm->start_code, task->mm->end_code, + task->mm->start_data, task->mm->end_data, bss_start, bss_end, + heap_start, heap_end, stack_start, stack_end, elf_base); return 0; } diff --git a/src/elf_helpers.h b/src/elf_helpers.h index 48d4777..4a70e72 100644 --- a/src/elf_helpers.h +++ b/src/elf_helpers.h @@ -17,7 +17,11 @@ static inline eh_u64 compute_usage_permyriad(eh_u64 total_ns, eh_u64 delta_ns) return (10000ULL * total_ns) / delta_ns; } -/* Compute BSS range from end_data and start_brk; returns 0 on invalid */ +/* Compute BSS range from end_data and start_brk; returns 0 on invalid + * BSS (Block Started by Symbol): Uninitialized data segment + * Note: Modern ELF binaries may have zero-length BSS if end_data == start_brk + * This is normal and not an error. + */ static inline int compute_bss_range(unsigned long end_data, unsigned long start_brk, unsigned long *out_start, @@ -33,7 +37,14 @@ static inline int compute_bss_range(unsigned long end_data, return 1; } -/* Compute heap range from start_brk and brk; returns 0 on invalid */ +/* Compute heap range from start_brk and brk; returns 0 on invalid + * Heap: Dynamic memory allocation region + * LIMITATION: This only tracks brk-based heap (traditional heap). + * Modern allocators (glibc malloc) also use mmap for large allocations + * and arena-based heaps, which are NOT included in this range. + * To see full heap usage, you would need to parse /proc/pid/maps for + * anonymous mappings marked as [heap] or unnamed mmap regions. + */ static inline int compute_heap_range(unsigned long start_brk, unsigned long brk, unsigned long *out_start, unsigned long *out_end) From f9fb9cfa15ba98b9392f744184ebfed69e88fd0a Mon Sep 17 00:00:00 2001 From: navidpadid Date: Thu, 22 Jan 2026 00:38:13 +0000 Subject: [PATCH 3/7] more testing and modularization --- README.md | 3 --- src/elf_det.c | 37 +++++++++++++++++++++++++++---------- src/elf_det_tests.c | 20 ++++++++++++++++++++ src/elf_helpers.h | 15 +++++++++++++++ 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 7d9800a..1b2430b 100644 --- a/README.md +++ b/README.md @@ -586,9 +586,6 @@ ls -la /proc/elf_det/ This project is licensed under **Dual BSD/GPL** license. -## Author - -**Navid Malekghaini** ## Contributing diff --git a/src/elf_det.c b/src/elf_det.c index 9302a64..0c847d8 100644 --- a/src/elf_det.c +++ b/src/elf_det.c @@ -33,6 +33,32 @@ static ssize_t procfile_write(struct file *, const char __user *, size_t, // det proc file_operations starts +/* Find the lower boundary of the stack VMA + * Iterates through VMAs to find the one containing start_stack + * Returns the vm_start (lower bound) of the stack VMA, or 0 if not found + */ +static unsigned long find_stack_vma_end(struct mm_struct *mm, + unsigned long start_stack) +{ + struct vm_area_struct *vma; + struct ma_state mas; + unsigned long stack_end = 0; + + mas_init(&mas, &mm->mm_mt, 0); + mas_for_each(&mas, vma, ULONG_MAX) + { + /* Use helper to check if start_stack is within this VMA */ + if (is_address_in_range(start_stack, vma->vm_start, + vma->vm_end)) { + /* Found the stack VMA */ + stack_end = vma->vm_start; /* Stack grows down */ + break; + } + } + + return stack_end; +} + // this function is the base function to gather information from kernel static int elfdet_show(struct seq_file *m, void *v) { @@ -87,16 +113,7 @@ static int elfdet_show(struct seq_file *m, void *v) /* Stack: Find the [stack] VMA for actual stack boundaries */ stack_start = task->mm->start_stack; - mas_set(&mas, 0); - mas_for_each(&mas, vma, ULONG_MAX) - { - if (vma->vm_start <= task->mm->start_stack && - vma->vm_end >= task->mm->start_stack) { - /* Found the stack VMA */ - stack_end = vma->vm_start; /* Stack grows down */ - break; - } - } + stack_end = find_stack_vma_end(task->mm, stack_start); /* BSS: uninitialized data between end_data and start_brk * May be zero-length in modern binaries diff --git a/src/elf_det_tests.c b/src/elf_det_tests.c index 8f22231..f037092 100644 --- a/src/elf_det_tests.c +++ b/src/elf_det_tests.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) #include "elf_helpers.h" #include +#include #include int main(void) @@ -38,6 +39,25 @@ int main(void) assert(ret1 == 1); assert(s == 10000UL && e == 10000UL); + /* is_address_in_range tests */ + /* Test address within range */ + assert(is_address_in_range(5000UL, 1000UL, 10000UL) == 1); + assert(is_address_in_range(1000UL, 1000UL, 10000UL) == 1); + + /* Test address at boundary (range_end is exclusive) */ + assert(is_address_in_range(10000UL, 1000UL, 10000UL) == 0); + + /* Test address outside range */ + assert(is_address_in_range(500UL, 1000UL, 10000UL) == 0); + assert(is_address_in_range(15000UL, 1000UL, 10000UL) == 0); + + /* Test invalid range (start > end) */ + assert(is_address_in_range(5000UL, 10000UL, 1000UL) == 0); + + /* Test edge cases */ + assert(is_address_in_range(0UL, 0UL, 1UL) == 1); + assert(is_address_in_range(ULONG_MAX - 1, 0UL, ULONG_MAX) == 1); + puts("elf_helpers tests passed"); return 0; } diff --git a/src/elf_helpers.h b/src/elf_helpers.h index 4a70e72..db97871 100644 --- a/src/elf_helpers.h +++ b/src/elf_helpers.h @@ -58,3 +58,18 @@ static inline int compute_heap_range(unsigned long start_brk, unsigned long brk, *out_end = brk; return 1; } + +/* Check if an address falls within a memory range (inclusive) + * Used for finding VMAs that contain specific addresses like stack + * Returns 1 if addr is within [range_start, range_end), 0 otherwise + */ +static inline int is_address_in_range(unsigned long addr, + unsigned long range_start, + unsigned long range_end) +{ + if (range_start > range_end) + return 0; + if (addr >= range_start && addr < range_end) + return 1; + return 0; +} From 80ce0b8ec6308288cf1f817c21caeff859d88d49 Mon Sep 17 00:00:00 2001 From: navidpadid Date: Thu, 22 Jan 2026 00:42:33 +0000 Subject: [PATCH 4/7] updated README --- README.md | 84 +++++-------------------------------------------------- 1 file changed, 7 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 1b2430b..8e16e94 100644 --- a/README.md +++ b/README.md @@ -35,39 +35,13 @@ The project consists of two main components: ``` kernel_module/ -├── .devcontainer/ # Development container configuration -│ ├── Dockerfile # Pre-installs: clang-format, sparse, cppcheck -│ └── devcontainer.json # Auto-configures Git hooks on startup -├── .github/ -│ └── workflows/ -│ └── ci.yml # GitHub Actions CI/CD with static analysis -├── scripts/ # Testing and utility scripts -│ ├── qemu-setup.sh # Setup QEMU testing environment -│ ├── qemu-run.sh # Run QEMU VM -│ ├── qemu-test.sh # Automated module testing in QEMU -│ ├── pre-commit.sh # Pre-commit hook script (auto-installed in container) -│ └── README.md # Scripts documentation -├── src/ -│ ├── elf_det.c # Kernel module source code -│ ├── proc_elf_ctrl.c # User-space controller program -│ ├── elf_det_tests.c # Unit tests for elf_det functions -│ ├── proc_elf_ctrl_tests.c # Unit tests for proc_elf_ctrl helpers -│ ├── elf_helpers.h # Helper functions for CPU usage and BSS range -│ ├── user_helpers.h # Helper functions for path building -│ └── Kbuild # Kernel build configuration -├── .clang-format # Code formatting configuration -├── .cppcheck-suppressions # Static analysis suppressions -├── .editorconfig # Editor configuration -├── Makefile # Build system with static analysis targets -├── .gitignore # Git ignore rules -└── README.md # This file - -Generated after build: -└── build/ # Build artifacts (created by make) - ├── elf_det.ko # Compiled kernel module - ├── proc_elf_ctrl # Compiled user program - ├── elf_det_tests # Compiled unit tests for elf_det - └── proc_elf_ctrl_tests # Compiled unit tests for proc_elf_ctrl +├── .devcontainer/ # Dev container config (Docker + VS Code setup) +├── .github/ # CI/CD workflows (GitHub Actions) +├── scripts/ # E2E isolated testing scripts (QEMU setup, e2e testing automation) +├── src/ # Source code (kernel module, user program, tests, helpers) +├── build/ # Build artifacts (generated by make) +├── Makefile # Build system with quality checks +└── README.md # Documentation ``` ## Prerequisites @@ -591,50 +565,6 @@ This project is licensed under **Dual BSD/GPL** license. Contributions, issues, and feature requests are welcome! -## Changelog - -### Version 1.3 -- Added `STACK_END` extraction by parsing stack VMA -- Fixed `ELF` column to show actual ELF base address (renamed to `ELF_BASE`) -- Clarified that ELF_BASE is the first VMA (PIE binary base) -- Stack now shows full range (start to end) -- Improved VMA iteration for stack boundary detection - -### Version 1.2.1 -- Added stack start address extraction (`STACK_START` column) -- Improved documentation of memory layout limitations -- Added comprehensive notes about BSS zero-length in modern binaries -- Documented brk-based heap limitation (mmap heaps not tracked) -- Clarified that rodata is merged with code section -- Enhanced code comments for better understanding -- Fixed potential confusion about "always zero" BSS - -### Version 1.2 -- Added heap start and end address extraction -- Enhanced memory layout analysis with heap region tracking -- Added `compute_heap_range()` helper function -- Updated unit tests to cover heap range computation -- Improved documentation with comprehensive heap information -- Updated output format to include HEAP_START and HEAP_END columns - -### Version 1.1 -- Integrated static analysis tools (clang-format, sparse, cppcheck, checkpatch) -- Automated Git pre-commit hooks for code quality -- Dev container with zero-configuration setup -- Enhanced CI/CD pipeline with static analysis checks -- Comprehensive code quality documentation - -### Version 1.0 -- Initial release with basic process information extraction -- Support for CPU usage, memory layout, and ELF sections -- User-space controller program -- Function-level unit tests for core functionality -- Dev container support for isolated development -- CI/CD pipeline with GitHub Actions -- QEMU testing environment for safe kernel module testing -- Comprehensive documentation and quick reference guides -- Dual BSD/GPL license - --- **Note**: This is an educational project demonstrating Linux kernel module development. Use responsibly and at your own risk. From 1e0fda4910fef40f8a0298ea0acec3ca6204f9be Mon Sep 17 00:00:00 2001 From: navidpadid Date: Thu, 22 Jan 2026 00:45:28 +0000 Subject: [PATCH 5/7] updated README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 8e16e94..b3c4717 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,8 @@ This project implements a Linux Kernel Module that provides access to process in - **Process ID (PID)** and **Process Name** - **CPU Usage** statistics -- **Memory Layout**: Code, Data, BSS, Heap, and Stack sections -- **ELF Binary** information - **Start/End addresses** for code, data, BSS, heap, and stack segments +- **ELF Binary** information The project consists of two main components: 1. **Kernel Module** (`elf_det.c`) - Runs in kernel space and gathers process information From 80113d40b2d6b8aa1929322a16767691d7126e6d Mon Sep 17 00:00:00 2001 From: navidpadid Date: Thu, 22 Jan 2026 00:56:05 +0000 Subject: [PATCH 6/7] modularized docs --- README.md | 526 +++++++++---------------------------------- docs/CODE_QUALITY.md | 120 ++++++++++ docs/SCRIPTS.md | 220 ++++++++++++++++++ docs/TECHNICAL.md | 109 +++++++++ docs/TESTING.md | 122 ++++++++++ scripts/README.md | 214 ------------------ 6 files changed, 674 insertions(+), 637 deletions(-) create mode 100644 docs/CODE_QUALITY.md create mode 100644 docs/SCRIPTS.md create mode 100644 docs/TECHNICAL.md create mode 100644 docs/TESTING.md delete mode 100644 scripts/README.md diff --git a/README.md b/README.md index b3c4717..9012cea 100644 --- a/README.md +++ b/README.md @@ -4,31 +4,39 @@ [![Last Commit](https://img.shields.io/github/last-commit/navidpadid/process-info-kernel-module?style=for-the-badge&logo=git&logoColor=white)](https://github.com/navidpadid/process-info-kernel-module/commits/main) [![License](https://img.shields.io/badge/License-Dual%20BSD%2FGPL-blue?style=for-the-badge)](LICENSE) -> A Linux kernel module (LKM) with a user-space controller that extracts detailed process information including memory layout and ELF sections. +> A Linux kernel module that extracts detailed process information including memory layout, CPU usage, and ELF sections via `/proc` filesystem. -## Overview +## Features -This project implements a Linux Kernel Module that provides access to process information through the `/proc` filesystem. The module exposes process details such as: +- **Process Memory Layout**: Code, Data, BSS, Heap, and Stack addresses +- **CPU Usage Tracking**: Real-time CPU percentage calculation +- **ELF Section Analysis**: Binary base address and section boundaries +- **Proc Interface**: Easy access through `/proc/elf_det/` +- **Comprehensive Testing**: Unit tests and QEMU-based E2E testing +- **Code Quality**: Pre-configured static analysis (sparse, cppcheck, checkpatch) -- **Process ID (PID)** and **Process Name** -- **CPU Usage** statistics -- **Start/End addresses** for code, data, BSS, heap, and stack segments -- **ELF Binary** information +## Quick Start -The project consists of two main components: -1. **Kernel Module** (`elf_det.c`) - Runs in kernel space and gathers process information -2. **User Program** (`proc_elf_ctrl.c`) - User-space controller to interact with the module +### Prerequisites -## Features +- **Docker** + **VS Code** with Remote - Containers extension +- Dev container includes everything: Ubuntu 24.04, kernel 6.8+ headers, build tools, static analysis + +### Build and Run -- **Process Memory Inspection**: View detailed memory layout of any running process -- **CPU Usage Tracking**: Real-time CPU usage percentage calculation -- **ELF Section Analysis**: Extract ELF binary sections (code, data, BSS) -- **Heap Analysis**: Track heap start and end addresses for dynamic memory allocation (brk-based) -- **Stack Tracking**: Monitor stack start address -- **Proc Filesystem Interface**: Easy interaction through `/proc/elf_det/` -- **Sequential File Operations**: Efficient data reading using kernel seq_file API -- **User-Friendly CLI**: Simple command-line interface for querying process information +1. Open project in VS Code → "Reopen in Container" +2. Build: + ```bash + make all + ``` +3. Install module: + ```bash + sudo make install + ``` +4. Run user program: + ```bash + ./build/proc_elf_ctrl + ``` ## Project Structure @@ -36,66 +44,11 @@ The project consists of two main components: kernel_module/ ├── .devcontainer/ # Dev container config (Docker + VS Code setup) ├── .github/ # CI/CD workflows (GitHub Actions) -├── scripts/ # E2E isolated testing scripts (QEMU setup, e2e testing automation) +├── docs/ # Detailed documentation +├── scripts/ # Testing scripts (QEMU setup, E2E testing automation) ├── src/ # Source code (kernel module, user program, tests, helpers) ├── build/ # Build artifacts (generated by make) -├── Makefile # Build system with quality checks -└── README.md # Documentation -``` - -## Prerequisites - -This project uses a **Dev Container** for development to ensure a consistent, fully-configured environment. - -**Required:** -- **Docker** installed and running -- **VS Code** with Remote - Containers extension -- **Internet connection** for initial container build - -**Included in container:** -- Ubuntu 24.04 with Kernel 6.8+ headers -- All build tools (gcc, make, kernel headers) -- Static analysis tools (clang-format, sparse, cppcheck) pre-installed -- Git pre-commit hooks automatically configured -- Zero manual configuration required - -## Building and Running - -### Using Dev Container - -1. Open the project in VS Code -2. Click "Reopen in Container" when prompted (or use Command Palette: "Remote-Containers: Reopen in Container") -3. Wait for the container to build and initialize (first time only) -4. Build the project: - -```bash -make all -``` - -This will build: -- `build/elf_det.ko` - The kernel module -- `build/proc_elf_ctrl` - The user program - -All dependencies, tools, and hooks are pre-configured automatically! - -## Usage - -### 1. Install the Kernel Module - -```bash -sudo make install -``` - -This loads the module into the kernel. Verify it's loaded: - -```bash -lsmod | grep elf_det -``` - -### 2. Run the User Program - -```bash -./build/proc_elf_ctrl +└── Makefile # Build system with quality checks ``` The program will prompt you to enter a process ID (PID). You can find PIDs using: @@ -144,156 +97,105 @@ For maximum safety, test the kernel module in an isolated QEMU virtual machine t ``` -### What QEMU Testing Does +## Example Output -- Downloads Ubuntu 24.04 VM image -- Configures VM with kernel headers -- Provides SSH access on port 2222 -- Completely isolates module testing from your host -- Automated build, install, test, and uninstall cycle +``` +PID NAME CPU(%) START_CODE END_CODE START_DATA END_DATA +BSS_START BSS_END HEAP_START HEAP_END STACK_START +STACK_END ELF_BASE +01234 bash 0.50 0x563a1234 0x563a5678 0x563a9abc 0x563adef0 +0x563adef0 0x563adef0 0x563b0000 0x563b8000 0x7ffd12345000 +0x7ffd12340000 0x563a1000 +``` -See [scripts/README.md](scripts/README.md) for detailed QEMU testing documentation. +**Note**: BSS_START and BSS_END may be equal (zero-length) in modern binaries - this is normal. ## Makefile Targets -### Build Targets - -| Target | Description | -|--------|-------------| -| `make all` | Build both kernel module and user program (default) | -| `make module` | Build kernel module only | -| `make user` | Build user program only | -| `make install` | Install kernel module (requires root) | -| `make uninstall` | Remove kernel module (requires root) | -| `make test` | Install module and run user program | -| `make unit` | Build and run function-level unit tests (no kernel required) | -| `make clean` | Remove all build artifacts | -| `make help` | Display help message | - -### Code Quality Targets - -| Target | Description | -|--------|-------------| -| `make check` | Run all static analysis checks (checkpatch + sparse + cppcheck) | -| `make checkpatch` | Check kernel coding style with checkpatch.pl | -| `make sparse` | Run sparse static analyzer for kernel code | -| `make cppcheck` | Run cppcheck static analyzer for C/C++ | -| `make format` | Format all source files with clang-format | -| `make format-check` | Check if code is properly formatted (CI-friendly) | - -## Technical Details - -### Kernel Module (`elf_det.c`) - -The kernel module creates entries in `/proc/elf_det/`: -- `/proc/elf_det/pid` - Write-only file to specify target PID -- `/proc/elf_det/det` - Read-only file to retrieve process information - -**Key Functions:** -- `elfdet_show()` - Main function to gather and format process information -- `procfile_write()` - Handles PID input from user space -- `procfile_read()` - Returns formatted process data - -**Memory Information Extracted:** -- **Code Section**: `start_code` to `end_code` - executable code region (includes rodata) -- **Data Section**: `start_data` to `end_data` - initialized data region -- **BSS Section**: `end_data` to `start_brk` - uninitialized data region -- **Heap Section**: `start_brk` to `brk` - brk-based dynamic memory allocation -- **Stack**: `start_stack` (top/base) to `stack_end` (current lower bound) -- **ELF Base**: Base address of the ELF binary (first VMA, typically lower than start_code for PIE) - -**Important Notes and Limitations:** - -1. **BSS May Be Zero-Length**: Modern ELF binaries often have `end_data == start_brk`, resulting in zero-length BSS. This is normal, not an error. - -2. **Read-Only Data (rodata)**: The read-only data segment is typically merged with the code section (`start_code` to `end_code`) in modern binaries. It's not shown separately. - -3. **Heap Limitation**: The heap shown is **brk-based only** (traditional heap managed by brk/sbrk syscalls). Modern allocators like glibc's malloc also use: - - **mmap-based allocations** for large requests (>128KB typically) - - **Arena heaps** (multiple heap regions) - - These are NOT included in the brk-based heap range shown - - To see full heap usage, parse `/proc/pid/maps` for anonymous `[heap]` entries and unnamed mmap regions - -4. **Stack**: Shows both `start_stack` (top/base) and `stack_end` (current lower boundary). The stack grows downward from start_stack. The actual current stack pointer (in CPU registers) may be anywhere between these bounds. - -**Kernel APIs Used:** -- `proc_fs.h` - Proc filesystem operations -- `seq_file.h` - Sequential file interface -- `sched.h` - Task/process structures -- `mm_types.h` - Memory management structures - -### User Program (`proc_elf_ctrl.c`) - -Simple C program that supports two modes: -1. Interactive: prompts for a PID, writes to `/proc/elf_det/pid`, then reads `/proc/elf_det/det` and prints two lines -2. Argument mode: run `./build/proc_elf_ctrl ` to write the PID and print exactly two lines non-interactively +```bash +make all # Build kernel module and user program +make install # Install kernel module (requires root) +make uninstall # Remove kernel module +make unit # Run unit tests (no kernel required) +make test # Install module and run user program -You can override the proc directory for testing with the environment variable `ELF_DET_PROC_DIR`. +make format # Format all source files +make check # Run all static analysis +make clean # Remove build artifacts +``` -Example: +## Testing +### Unit Tests (Recommended First) ```bash -ELF_DET_PROC_DIR=/tmp/fakeproc ./build/proc_elf_ctrl 12345 +make unit ``` +Runs pure function tests without kernel dependencies. -Internally, path construction is handled via helper `build_proc_path()`. - -Helper headers used: -- `src/user_helpers.h` – path building with env override -- `src/elf_helpers.h` – pure functions for CPU usage, BSS range, and heap range - -## Code Quality and Static Analysis - -This project includes comprehensive static analysis and code formatting tools to ensure high code quality and compliance with Linux kernel coding standards. +### QEMU Testing (Safe Kernel Testing) +```bash +./scripts/qemu-setup.sh # One-time setup +./scripts/qemu-run.sh # Start VM +./scripts/qemu-test.sh # Run automated tests +``` -### Installing Analysis Tools +See [docs/TESTING.md](docs/TESTING.md) for detailed testing documentation. -Run the installation script to install all required tools: +## Documentation -```bash -./scripts/install-analysis-tools.sh -``` +- [TESTING.md](docs/TESTING.md) - Unit tests, QEMU testing, troubleshooting +- [TECHNICAL.md](docs/TECHNICAL.md) - Kernel module details, memory layout, limitations +- [CODE_QUALITY.md](docs/CODE_QUALITY.md) - Static analysis, code formatting, best practices +- [SCRIPTS.md](docs/SCRIPTS.md) - Detailed script documentation -This installs: -- **clang-format**: Code formatting according to kernel style -- **sparse**: Semantic parser for C, designed for kernel code -- **cppcheck**: General C/C++ static analysis -- **checkpatch.pl**: Official kernel coding style checker (requires kernel sources) +## Important Notes -### Running Static Analysis +- **Dev container recommended**: Provides fully configured environment +- **Root required**: Loading/unloading kernel modules needs sudo +- **QEMU testing**: Safest way to test - isolates from host kernel +- **BSS often zero**: Modern binaries frequently have zero-length BSS +- **Heap limitation**: Only tracks brk-based heap, not mmap allocations -Run all checks at once: +## License -```bash -make check -``` +Dual BSD/GPL - Choose the license that works best for you: +- **GPL**: Required for Linux kernel compatibility +- **BSD**: Permissive for other uses -Or run individual checks: +## Contributing -```bash -# Check kernel coding style -make checkpatch +Contributions welcome! The project includes: +- Pre-configured dev container +- Automated testing (unit tests + QEMU E2E) +- Static analysis and formatting tools +- GitHub Actions CI/CD -# Run sparse static analyzer -make sparse +## Changelog -# Run cppcheck analyzer -make cppcheck -``` +### Version 1.3 (Current) +- Added `STACK_END` and `ELF_BASE` extraction +- Extracted stack finding logic with unit tests +- Improved VMA iteration with maple tree API +- Comprehensive documentation in docs/ folder -### Code Formatting +### Version 1.2 +- Added heap start/end extraction +- Added `compute_heap_range()` helper function +- Documented memory layout limitations -Format all source files automatically: +### Version 1.1 +- Integrated static analysis tools +- Dev container with zero-configuration setup +- Enhanced CI/CD pipeline -```bash -make format -``` +### Version 1.0 +- Initial release +- Basic process information extraction +- QEMU testing environment -Check if code is properly formatted (useful for CI/CD): +--- -```bash -make format-check -``` +**Educational Project**: Demonstrates Linux kernel module development. Use at your own risk. ### Configuration Files @@ -344,226 +246,4 @@ The module has been tested on: **Kernel Compatibility Notes:** - Kernel 5.6+ required (proc_ops API) - Kernel 6.8+ recommended (VMA iterator API) -- The code has been updated to use modern kernel APIs including VMA iterators and proc_ops - -**Safe Testing Options:** -### Function-Level Unit Tests - -Run pure function tests (no kernel required): - -```bash -make unit -``` - -This builds and runs: -- `src/elf_det_tests.c` – verifies `compute_usage_permyriad()`, `compute_bss_range()`, and `compute_heap_range()` -- `src/proc_elf_ctrl_tests.c` – verifies `build_proc_path()` with and without `ELF_DET_PROC_DIR` - -Artifacts are created under `build/`. -1. **Dev Container** (current setup) - Isolated from host -2. **QEMU VM** (recommended for extra safety from kernel) - See [scripts/README.md](scripts/README.md) -3. **Cloud VM** - Disposable testing environment - - -## Important Notes - -- **Use the dev container** for development - it provides a consistent, fully-configured environment -- **Root privileges** are required to load/unload kernel modules -- The container includes **Ubuntu 24.04 with Kernel 6.8+** (VMA iterator API support) -- Accessing invalid PIDs may cause undefined behavior -- Always unload the module before rebuilding -- **Static analysis tools** and **Git hooks** are automatically configured on container startup - -## Static Analysis and Code Quality - -This project includes comprehensive static analysis and code formatting tools to ensure high code quality and compliance with Linux kernel coding standards. - -**All tools and hooks are automatically installed and configured in the dev container.** No manual setup required! - -### Tools Integrated - -The following tools are included: - -#### 1. clang-format -**Purpose**: Automatic code formatting -**Standard**: Linux kernel coding style -**Configuration**: `.clang-format` - -**Features**: -- 8-space tabs (kernel standard) -- 80-column line limit -- Linux brace style -- Consistent spacing and alignment - -**Usage**: -```bash -make format # Format all files -make format-check # Check formatting (CI-friendly) -``` - -#### 2. checkpatch.pl -**Purpose**: Kernel coding style compliance -**Source**: Official Linux kernel scripts - -**Checks**: -- Indentation and spacing rules -- Line length limits (80 columns preferred) -- Function declaration style -- Comment formatting (/* */ style) -- Macro usage patterns -- Variable naming conventions - -**Usage**: -```bash -make checkpatch -``` - -#### 3. sparse -**Purpose**: Semantic analysis for C code -**Specialty**: Kernel-specific checks - -**Detects**: -- Type confusion errors -- Endianness issues (`__be32`, `__le32`) -- Lock context imbalances -- Address space mismatches (`__user`, `__kernel`) -- Null pointer dereferences - -**Usage**: -```bash -make sparse -``` - -#### 4. cppcheck -**Purpose**: General C/C++ static analysis -**Configuration**: `.cppcheck-suppressions` - -**Detects**: -- Memory leaks -- Buffer overflows -- Uninitialized variables -- Dead code -- Logic errors - -**Usage**: -```bash -make cppcheck -``` - -### Running Static Analysis - -Run all checks at once: -```bash -make check -``` - -Or run individual checks: -```bash -make checkpatch # Kernel coding style -make sparse # Kernel static analysis -make cppcheck # General C/C++ analysis -make format # Format all code -``` - -### Configuration Files - -- **`.clang-format`** - Code formatting rules (Linux kernel style) -- **`.cppcheck-suppressions`** - Suppression list for false positives -- **`.editorconfig`** - Editor configuration for consistent coding style - -### Git Hooks - -Pre-commit hooks are automatically installed on container startup. - -The pre-commit hook runs: -- Code formatting checks -- Cppcheck static analysis -- Checkpatch coding style validation - -To bypass hooks (use sparingly): -```bash -git commit --no-verify -m "message" -``` - -### Best Practices - -**Follow Linux Kernel Coding Style:** -- Use tabs (8 spaces), not spaces for indentation -- 80 column limit for code -- Opening brace on same line (except functions) -- Space after keywords: `if (`, `while (`, `for (` -- No space after function names: `function(arg)` -- Use C89-style comments: `/* comment */` - -**Example:** -```c -int example_function(int param) -{ - if (param > 0) { - /* Comment style: C89 */ - return param * 2; - } - return 0; -} -``` - -**Development Workflow:** - -```bash -# Everything is ready - just start coding! - -# Format code before committing -make format - -# Run all checks -make check - -# Commit (hooks run automatically) -git commit -m "Your message" -``` - -## Troubleshooting - -### Module won't load - -```bash -# Check kernel logs -dmesg | tail -n 20 - -# Verify kernel headers are installed -ls /lib/modules/$(uname -r)/build -``` - -### Build errors - -```bash -# Install missing dependencies -sudo apt-get install -y build-essential linux-headers-$(uname -r) - -# Clean and rebuild -make clean -make all -``` - -### Permission denied when running user program - -```bash -# Ensure module is loaded -lsmod | grep elf_det - -# Check proc entries exist -ls -la /proc/elf_det/ -``` - -## License - -This project is licensed under **Dual BSD/GPL** license. - - -## Contributing - -Contributions, issues, and feature requests are welcome! - ---- - -**Note**: This is an educational project demonstrating Linux kernel module development. Use responsibly and at your own risk. +- The code has been updated to use modern kernel APIs including VMA iterators and proc_ops**Educational Project**: Demonstrates Linux kernel module development. Use at your own risk. diff --git a/docs/CODE_QUALITY.md b/docs/CODE_QUALITY.md new file mode 100644 index 0000000..ecb07a6 --- /dev/null +++ b/docs/CODE_QUALITY.md @@ -0,0 +1,120 @@ +# Code Quality and Static Analysis + +This project includes comprehensive static analysis and code formatting tools to ensure high code quality and compliance with Linux kernel coding standards. + +**All tools and hooks are automatically installed and configured in the dev container.** No manual setup required! + +## Quick Reference + +```bash +make format # Format all source files +make format-check # Check if code is properly formatted (CI-friendly) +make check # Run all static analysis checks +make checkpatch # Kernel coding style +make sparse # Kernel static analysis +make cppcheck # General C/C++ analysis +``` + +## Tools Integrated + +### 1. clang-format +**Purpose**: Automatic code formatting +**Standard**: Linux kernel coding style +**Configuration**: `.clang-format` + +**Features**: +- 8-space tabs (kernel standard) +- 80-column line limit +- Linux brace style +- Consistent spacing and alignment + +### 2. checkpatch.pl +**Purpose**: Kernel coding style compliance +**Source**: Official Linux kernel scripts + +**Checks**: +- Indentation and spacing rules +- Line length limits (80 columns preferred) +- Function declaration style +- Comment formatting (/* */ style) +- Macro usage patterns +- Variable naming conventions + +### 3. sparse +**Purpose**: Semantic analysis for C code +**Specialty**: Kernel-specific checks + +**Detects**: +- Type confusion errors +- Endianness issues (`__be32`, `__le32`) +- Lock context imbalances +- Address space mismatches (`__user`, `__kernel`) +- Null pointer dereferences + +### 4. cppcheck +**Purpose**: General C/C++ static analysis +**Configuration**: `.cppcheck-suppressions` + +**Detects**: +- Memory leaks +- Buffer overflows +- Uninitialized variables +- Dead code +- Logic errors + +## Configuration Files + +- **`.clang-format`** - Code formatting rules (Linux kernel style) +- **`.cppcheck-suppressions`** - Suppression list for false positives +- **`.editorconfig`** - Editor configuration for consistent coding style + +## Git Hooks + +Pre-commit hooks are automatically installed on container startup. + +The pre-commit hook runs: +- Code formatting checks +- Cppcheck static analysis +- Checkpatch coding style validation + +To bypass hooks (use sparingly): +```bash +git commit --no-verify -m "message" +``` + +## Best Practices + +**Follow Linux Kernel Coding Style:** +- Use tabs (8 spaces), not spaces for indentation +- 80 column limit for code +- Opening brace on same line (except functions) +- Space after keywords: `if (`, `while (`, `for (` +- No space after function names: `function(arg)` +- Use C89-style comments: `/* comment */` + +**Example:** +```c +int example_function(int param) +{ + if (param > 0) { + /* Comment style: C89 */ + return param * 2; + } + return 0; +} +``` + +## Development Workflow + +```bash +# Everything is ready - just start coding! + +# Format code before committing +make format + +# Run all checks +make check + +# Commit (hooks run automatically) +git commit -m "Your message" +``` diff --git a/docs/SCRIPTS.md b/docs/SCRIPTS.md new file mode 100644 index 0000000..f8bd491 --- /dev/null +++ b/docs/SCRIPTS.md @@ -0,0 +1,220 @@ +# Scripts Documentation + +Scripts for testing the Linux Process Information Kernel Module in isolated QEMU virtual machines. + +## Quick Reference + +```bash +# QEMU Testing +./scripts/qemu-setup.sh # One-time setup +./scripts/qemu-run.sh # Start VM +./scripts/qemu-test.sh # Automated tests (run from host in another terminal) + +# Other utilities +./scripts/pre-commit.sh # Pre-commit hook (auto-installed in dev container) +./scripts/quick-reference.sh # Display quick reference guide +``` + +## Script Descriptions + +### `qemu-setup.sh` +**Purpose**: One-time setup of QEMU testing environment + +**What it does**: +- Downloads Ubuntu 24.04 cloud image (~700MB) +- Creates cloud-init configuration for VM +- Sets up VM with kernel headers pre-installed +- Configures SSH access with default credentials + +**Requirements**: +- `qemu-system-x86_64` +- `qemu-img` +- `cloud-localds` (from cloud-image-utils package) + +**Output**: Creates `qemu-env/` directory with VM image and cloud-init config + +### `qemu-run.sh` +**Purpose**: Start the QEMU virtual machine + +**What it does**: +- Starts QEMU VM with appropriate settings +- Forwards SSH port 2222 to VM's port 22 +- Allocates 2GB RAM and 2 CPU cores +- Enables KVM acceleration if available +- Provides serial console access + +**VM Access**: +- SSH: `ssh -p 2222 ubuntu@localhost` +- Default password: `ubuntu` +- Exit console: Press Ctrl+A then X + +**Note**: First boot takes 1-2 minutes for cloud-init to complete. + +### `qemu-test.sh` +**Purpose**: Automated end-to-end testing in QEMU VM + +**What it does**: +1. Syncs project files to VM +2. Builds kernel module and user program in VM +3. Loads kernel module +4. Runs user program with test process +5. Captures and displays output +6. Unloads kernel module +7. Cleans up + +**Requirements**: +- QEMU VM must be running (`qemu-run.sh`) +- SSH access configured (done by `qemu-setup.sh`) + +**Usage**: +```bash +# Start VM in one terminal +./scripts/qemu-run.sh + +# Run tests from another terminal +./scripts/qemu-test.sh +``` + +**Output**: Shows build process, module loading, test results, and kernel logs. + +### `pre-commit.sh` +**Purpose**: Git pre-commit hook for code quality + +**What it does**: +- Runs code formatting checks +- Executes cppcheck static analysis +- Validates kernel coding style with checkpatch + +**Installation**: Automatically installed in dev container on startup. + +**Manual bypass** (use sparingly): +```bash +git commit --no-verify -m "message" +``` + +### `quick-reference.sh` +**Purpose**: Display comprehensive quick reference guide + +**What it shows**: +- Local testing commands +- QEMU setup and usage +- Build targets +- Memory information extracted +- Important limitations +- Troubleshooting tips + +**Usage**: +```bash +./scripts/quick-reference.sh +``` + +## QEMU VM Details + +### VM Specifications +- **OS**: Ubuntu 24.04 LTS +- **Kernel**: 6.8+ +- **RAM**: 2GB +- **CPUs**: 2 cores +- **Disk**: 10GB (cloud image) +- **Network**: User-mode networking with port forwarding + +### Default Credentials +- **Username**: `ubuntu` +- **Password**: `ubuntu` +- **Note**: Change password after first login for security + +### Port Forwarding +- Host port 2222 → VM port 22 (SSH) + +### SSH Key Setup (Optional) +To avoid password prompts: + +```bash +# Generate SSH key if you don't have one +ssh-keygen -t ed25519 + +# Copy to VM +ssh-copy-id -p 2222 ubuntu@localhost +``` + +### File Transfer + +**Copy TO VM**: +```bash +scp -P 2222 localfile.txt ubuntu@localhost:~/ +``` + +**Copy FROM VM**: +```bash +scp -P 2222 ubuntu@localhost:~/remotefile.txt ./ +``` + +**Sync directory** (used by qemu-test.sh): +```bash +rsync -avz --exclude='.git' --exclude='build' \ + -e "ssh -p 2222 -o StrictHostKeyChecking=no" \ + ./ ubuntu@localhost:~/kernel_module/ +``` + +## Cleanup and Maintenance + +### Remove QEMU Environment +```bash +rm -rf scripts/qemu-env/ +``` + +### Reinstall Fresh VM +```bash +rm -rf scripts/qemu-env/ +./scripts/qemu-setup.sh +``` + +### Check VM Status +```bash +# Check if QEMU is running +ps aux | grep qemu + +# Test SSH connection +ssh -p 2222 ubuntu@localhost echo "VM is accessible" +``` + +## Troubleshooting + +### Cannot connect to VM +1. Check if VM is running: `ps aux | grep qemu` +2. Wait for cloud-init to complete (1-2 minutes on first boot) +3. Verify port forwarding: `netstat -ln | grep 2222` +4. Check VM console for errors (Ctrl+A then C in qemu-run.sh) + +### VM is slow +1. Ensure KVM acceleration is enabled: `ls /dev/kvm` +2. Check CPU/memory allocation in `qemu-run.sh` +3. Verify host system has sufficient resources + +### Build fails in VM +1. Check kernel headers: `ls /lib/modules/$(uname -r)/build` +2. Update VM packages: `sudo apt update && sudo apt upgrade` +3. Verify project files synced correctly + +### Module won't load +1. Check kernel logs: `sudo dmesg | tail -20` +2. Verify kernel version compatibility +3. Ensure no conflicting modules loaded + +## Benefits of QEMU Testing + +- **Safe**: Kernel panics won't crash your host system +- **Isolated**: No risk to host kernel or data +- **Reproducible**: Clean VM state for each test +- **Fast**: Quick VM reset and rebuild +- **Automated**: Full CI/CD integration possible +- **Realistic**: Tests in real Linux kernel environment + +## Alternative Testing Options + +1. **Dev Container** (current setup) - Isolated from host +2. **QEMU VM** (recommended) - Extra safety from kernel crashes +3. **Cloud VM** - Disposable testing environment +4. **Physical test machine** - Dedicated hardware for kernel development + +For kernel module development, QEMU offers the best balance of safety, speed, and realism. diff --git a/docs/TECHNICAL.md b/docs/TECHNICAL.md new file mode 100644 index 0000000..7e3ae22 --- /dev/null +++ b/docs/TECHNICAL.md @@ -0,0 +1,109 @@ +# Technical Details + +## Kernel Module (`elf_det.c`) + +The kernel module creates entries in `/proc/elf_det/`: +- `/proc/elf_det/pid` - Write-only file to specify target PID +- `/proc/elf_det/det` - Read-only file to retrieve process information + +### Key Functions + +- `elfdet_show()` - Main function to gather and format process information +- `find_stack_vma_end()` - Finds stack VMA lower boundary by iterating VMAs +- `procfile_write()` - Handles PID input from user space +- `procfile_read()` - Returns formatted process data + +### Memory Information Extracted + +| Field | Description | Source | +|-------|-------------|--------| +| **Code Section** | `start_code` to `end_code` | Executable code region (includes rodata) | +| **Data Section** | `start_data` to `end_data` | Initialized data region | +| **BSS Section** | `end_data` to `start_brk` | Uninitialized data region | +| **Heap Section** | `start_brk` to `brk` | brk-based dynamic memory allocation | +| **Stack** | `start_stack` to `stack_end` | Stack region (grows downward) | +| **ELF Base** | First VMA start | Base address of ELF binary (for PIE) | + +### Important Notes and Limitations + +#### 1. BSS May Be Zero-Length +Modern ELF binaries often have `end_data == start_brk`, resulting in zero-length BSS. This is **normal**, not an error. + +#### 2. Read-Only Data (rodata) +The read-only data segment is typically merged with the code section (`start_code` to `end_code`) in modern binaries. It's not shown separately. + +#### 3. Heap Limitation +The heap shown is **brk-based only** (traditional heap managed by brk/sbrk syscalls). Modern allocators like glibc's malloc also use: +- **mmap-based allocations** for large requests (>128KB typically) +- **Arena heaps** (multiple heap regions) +- These are NOT included in the brk-based heap range shown +- To see full heap usage, parse `/proc/pid/maps` for anonymous `[heap]` entries and unnamed mmap regions + +#### 4. Stack +Shows both `start_stack` (top/base) and `stack_end` (current lower boundary). The stack grows downward from start_stack. The actual current stack pointer (in CPU registers) may be anywhere between these bounds. + +### Kernel APIs Used + +- `proc_fs.h` - Proc filesystem operations +- `seq_file.h` - Sequential file interface +- `sched.h` - Task/process structures +- `mm_types.h` - Memory management structures +- Maple tree API - Modern VMA iteration (kernel 6.8+) + +## User Program (`proc_elf_ctrl.c`) + +Simple C program that supports two modes: + +### Interactive Mode +```bash +./build/proc_elf_ctrl +``` +Prompts for a PID, writes to `/proc/elf_det/pid`, then reads `/proc/elf_det/det` and prints output. + +### Argument Mode +```bash +./build/proc_elf_ctrl +``` +Non-interactive mode - write PID and print exactly two lines. + +### Environment Override + +You can override the proc directory for testing: + +```bash +ELF_DET_PROC_DIR=/tmp/fakeproc ./build/proc_elf_ctrl 12345 +``` + +Internally, path construction is handled via `build_proc_path()`. + +## Helper Libraries + +### `src/elf_helpers.h` +Pure functions for CPU usage, BSS range, heap range, and address range checking: +- `compute_usage_permyriad()` - CPU usage calculation +- `compute_bss_range()` - BSS boundary validation +- `compute_heap_range()` - Heap boundary validation +- `is_address_in_range()` - Address containment check + +Works in both kernel and user space contexts. + +### `src/user_helpers.h` +Path building with environment override: +- `build_proc_path()` - Constructs `/proc/elf_det/` paths with `ELF_DET_PROC_DIR` support + +## Output Format + +``` +PID NAME CPU(%) START_CODE END_CODE START_DATA END_DATA +BSS_START BSS_END HEAP_START HEAP_END STACK_START +STACK_END ELF_BASE +``` + +Example: +``` +01234 bash 0.50 0x0000563a1234 0x0000563a5678 0x0000563a9abc +0x0000563adef0 0x0000563adef0 0x0000563adef0 0x0000563b0000 +0x0000563b8000 0x00007ffd12345000 0x00007ffd12340000 0x0000563a1000 +``` + +**Note**: BSS_START and BSS_END may be equal (zero-length BSS) in modern ELF binaries. This is normal. diff --git a/docs/TESTING.md b/docs/TESTING.md new file mode 100644 index 0000000..7f4e4fb --- /dev/null +++ b/docs/TESTING.md @@ -0,0 +1,122 @@ +# Testing Guide + +## Unit Tests (No Kernel Required) + +Run pure function tests without loading any kernel modules: + +```bash +make unit +``` + +This builds and runs: +- `src/elf_det_tests.c` – verifies `compute_usage_permyriad()`, `compute_bss_range()`, `compute_heap_range()`, and `is_address_in_range()` +- `src/proc_elf_ctrl_tests.c` – verifies `build_proc_path()` with and without `ELF_DET_PROC_DIR` + +Artifacts are created under `build/`. + +## QEMU Testing (Recommended) + +For maximum safety, test the kernel module in an isolated QEMU virtual machine. + +### Quick Start + +```bash +# One-time setup +./scripts/qemu-setup.sh + +# Start VM +./scripts/qemu-run.sh + +# In another terminal, run automated tests +./scripts/qemu-test.sh +``` + +### What QEMU Testing Does + +- Downloads Ubuntu 24.04 VM image +- Configures VM with kernel headers +- Provides SSH access on port 2222 +- Completely isolates module testing from your host +- Automated build, install, test, and uninstall cycle + +### Manual Testing in QEMU + +After starting the VM with `./scripts/qemu-run.sh`: + +```bash +# SSH into the VM +ssh -p 2222 ubuntu@localhost +# Password: ubuntu + +# Inside VM - build and test +cd kernel_module +make clean && make all +sudo make install +./build/proc_elf_ctrl + +# Check kernel logs +sudo dmesg | tail -20 + +# Unload module +sudo make uninstall +``` + +### VM Access + +- **SSH**: `ssh -p 2222 ubuntu@localhost` +- **Password**: `ubuntu` (change after first login) +- **Exit QEMU console**: Ctrl+A then X +- **Copy files TO VM**: `scp -P 2222 file.txt ubuntu@localhost:~/` +- **Copy files FROM VM**: `scp -P 2222 ubuntu@localhost:~/file.txt ./` + +### Cleanup + +```bash +# Remove QEMU environment and start fresh +rm -rf scripts/qemu-env/ +./scripts/qemu-setup.sh +``` + +## Kernel Compatibility + +The module has been tested on: +- Ubuntu 20.04 LTS (Kernel 5.15+) +- Ubuntu 22.04 LTS (Kernel 5.19+) +- Ubuntu 24.04 LTS (Kernel 6.8+) + +**Requirements:** +- Kernel 5.6+ required (proc_ops API) +- Kernel 6.8+ recommended (VMA iterator API with maple tree) + +## Troubleshooting + +### Module won't load + +```bash +# Check kernel logs +dmesg | tail -n 20 + +# Verify kernel headers are installed +ls /lib/modules/$(uname -r)/build +``` + +### Build errors + +```bash +# Install missing dependencies +sudo apt-get install -y build-essential linux-headers-$(uname -r) + +# Clean and rebuild +make clean +make all +``` + +### Permission denied when running user program + +```bash +# Ensure module is loaded +lsmod | grep elf_det + +# Check proc entries exist +ls -la /proc/elf_det/ +``` diff --git a/scripts/README.md b/scripts/README.md deleted file mode 100644 index e52699d..0000000 --- a/scripts/README.md +++ /dev/null @@ -1,214 +0,0 @@ -# Testing Scripts - -Scripts for testing the Linux Process Information Kernel Module in isolated QEMU virtual machines. - -## Overview - -This directory contains scripts for: -- **QEMU Testing**: Safely test kernel modules in isolated virtual machines - -**Note**: All development should be done in the dev container, which includes pre-configured static analysis tools and Git hooks. - -## Quick Start - -### QEMU Testing - -```bash -# 1. Setup QEMU environment (one-time setup) -./scripts/qemu-setup.sh - -# 2. Start the QEMU VM -./scripts/qemu-run.sh - -# 3. In another terminal, run automated tests -./scripts/qemu-test.sh -``` - -## Script Descriptions - -### QEMU Testing Scripts - -#### `qemu-setup.sh` -- Downloads Ubuntu 24.04 cloud image -- Creates cloud-init configuration -- Sets up VM with kernel headers pre-installed -- Only needs to be run once - -**Requirements:** -- `qemu-system-x86_64` -- `qemu-img` -- `cloud-localds` (from cloud-image-utils package) - -#### `qemu-run.sh` -- Starts the QEMU VM with appropriate settings -- Forwards SSH port 2222 to VM's port 22 -- Allocates 2GB RAM and 2 CPU cores -- Enables KVM acceleration if available - -**VM Access:** -- SSH: `ssh -p 2222 ubuntu@localhost` -- Password: `ubuntu` -- Exit QEMU: Press `Ctrl+A` then `X` - -#### `qemu-test.sh` -- Automated end-to-end testing script (run from host) -- Builds kernel module and user program locally -- Copies files to VM via SCP -- Installs module, runs tests, and uninstalls cleanly -- Shows kernel logs and test results -- Verifies module functionality in isolated environment - -**Prerequisites:** -- VM must be running (`qemu-run.sh`) -- SSH must be accessible on port 2222 - -#### `quick-reference.sh` -- Quick reference guide for common QEMU commands -- Display usage: `./scripts/quick-reference.sh` -- Includes setup, testing, and troubleshooting commands - -### Static Analysis - -**Note**: All tools and hooks are automatically installed and configured in the dev container. - -#### `pre-commit.sh` -- Git pre-commit hook script (automatically installed in dev container) -- Runs formatting, cppcheck, and checkpatch on staged files -- Can be bypassed with `git commit --no-verify` if needed - -**Checks Performed:** -- Code formatting compliance (clang-format) -- Cppcheck static analysis -- Kernel coding style (checkpatch) - -## Code Quality Workflow - -All tools are pre-configured in the dev container: - -```bash -make format # Format code -make check # Run all checks -git commit # Hooks run automatically -``` - -### During Development -```bash -# Format code before committing -make format - -# Run all static analysis checks -make check - -# Individual checks -make checkpatch # Kernel coding style -make sparse # Kernel static analysis -make cppcheck # General C/C++ analysis -``` - -### Pre-Commit -If Git hooks are installed, checks run automatically: -```bash -git commit -m "Your commit message" -# Hooks run automatically and will fail commit if issues found - -# To skip hooks (use sparingly) -git commit --no-verify -m "Your commit message" -``` - -## Manual Testing - -If you prefer manual testing: - -```bash -# Start VM -./scripts/qemu-run.sh - -# In another terminal, copy files -scp -P 2222 -r build src/Kbuild Makefile ubuntu@localhost:~/ - -# SSH into VM -ssh -p 2222 ubuntu@localhost - -# Inside VM -cd ~/ -make clean && make all - -# Run unit tests (no kernel required) -make unit - -# Test kernel module -sudo make install -lsmod | grep elf_det -./build/proc_elf_ctrl -sudo make uninstall -``` - -## Troubleshooting - -**VM won't start:** -- Ensure QEMU is installed -- Run setup script first: `./scripts/qemu-setup.sh` - -**Can't connect via SSH:** -- Wait 1-2 minutes after first boot for cloud-init -- Check VM is running: `ps aux | grep qemu` - -**KVM not available:** -- Normal on macOS or nested virtualization -- VM will run slower but still work - -**Module won't load:** -- Check kernel headers: `uname -r` and `ls /lib/modules/$(uname -r)/build` -- Rebuild inside VM: `make clean && make all` - -## Why QEMU Testing? - -Testing kernel modules in QEMU provides critical safety benefits: - -- **Complete Isolation**: Host kernel remains untouched -- **Safe Crash Recovery**: Simply restart the VM if module crashes -- **No Risk to Host**: System instability won't affect your machine -- **Kernel Version Control**: Test on specific kernel versions -- **Easy Reset**: Delete VM and start fresh anytime -- **Reproducible Environment**: Consistent testing across systems -- **CI/CD Integration**: Automate testing in isolated environments - -## Testing Workflow - -1. **Unit Tests First**: Run `make unit` to test pure functions locally (no kernel required) -2. **QEMU Integration**: Use QEMU scripts to test full kernel module in isolation -3. **Dev Container**: Use provided dev container for consistent build environment -4. **Production**: Only deploy to production systems after thorough QEMU testing - -## File Locations - -- VM images: `scripts/qemu-env/` -- Cloud-init: `scripts/qemu-env/user-data.yaml` -- Disk image: `scripts/qemu-env/ubuntu-24.04.img` - -## Additional Resources - -- **Main README**: [../README.md](../README.md) - Complete project documentation -- **Quick Reference**: Run `./scripts/quick-reference.sh` for command cheat sheet -- **Makefile Targets**: See main README for all available build and test targets - -## Cleanup - -To remove QEMU environment: -```bash -rm -rf scripts/qemu-env/ -``` - -To start fresh: -```bash -rm -rf scripts/qemu-env/ -./scripts/qemu-setup.sh -``` - -## Notes - -- First boot takes 1-2 minutes for cloud-init to complete -- VM uses Ubuntu 24.04 LTS with Kernel 6.8+ -- KVM acceleration is automatically enabled if available -- Default credentials: ubuntu/ubuntu (change after first login) -- SSH port forwarding: Host port 2222 → VM port 22 From 9df35c0aacd4d3d8d5be63c10783a847a4331cbc Mon Sep 17 00:00:00 2001 From: navidpadid Date: Thu, 22 Jan 2026 01:00:50 +0000 Subject: [PATCH 7/7] release workflow added --- .github/workflows/release.yml | 174 ++++++++++++++++++++++++++++++++ README.md | 1 + docs/RELEASE.md | 183 ++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 docs/RELEASE.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2865186 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,174 @@ +name: Release + +on: + workflow_dispatch: + inputs: + version_type: + description: 'Version bump type' + required: true + type: choice + options: + - patch + - minor + - major + pull_request: + types: [closed] + branches: + - main + +jobs: + release: + if: | + github.event_name == 'workflow_dispatch' || + (github.event.pull_request.merged == true && + (contains(github.event.pull_request.labels.*.name, 'release:major') || + contains(github.event.pull_request.labels.*.name, 'release:minor') || + contains(github.event.pull_request.labels.*.name, 'release:patch'))) + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Determine version bump type + id: version_type + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "type=${{ inputs.version_type }}" >> $GITHUB_OUTPUT + elif [[ "${{ contains(github.event.pull_request.labels.*.name, 'release:major') }}" == "true" ]]; then + echo "type=major" >> $GITHUB_OUTPUT + elif [[ "${{ contains(github.event.pull_request.labels.*.name, 'release:minor') }}" == "true" ]]; then + echo "type=minor" >> $GITHUB_OUTPUT + elif [[ "${{ contains(github.event.pull_request.labels.*.name, 'release:patch') }}" == "true" ]]; then + echo "type=patch" >> $GITHUB_OUTPUT + else + echo "type=none" >> $GITHUB_OUTPUT + fi + + - name: Get current version + id: current_version + run: | + # Try to get the latest tag, default to 1.3.0 if no tags exist + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.3.0") + echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT + # Remove 'v' prefix if present + VERSION=${LATEST_TAG#v} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Current version: $VERSION" + + - name: Calculate new version + id: new_version + run: | + CURRENT="${{ steps.current_version.outputs.version }}" + TYPE="${{ steps.version_type.outputs.type }}" + + # Parse current version + IFS='.' read -r -a VERSION_PARTS <<< "$CURRENT" + MAJOR="${VERSION_PARTS[0]}" + MINOR="${VERSION_PARTS[1]}" + PATCH="${VERSION_PARTS[2]}" + + # Bump version based on type + case "$TYPE" in + major) + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + ;; + minor) + MINOR=$((MINOR + 1)) + PATCH=0 + ;; + patch) + PATCH=$((PATCH + 1)) + ;; + *) + echo "No valid version type found" + exit 1 + ;; + esac + + NEW_VERSION="$MAJOR.$MINOR.$PATCH" + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "tag=v$NEW_VERSION" >> $GITHUB_OUTPUT + echo "New version: $NEW_VERSION" + + - name: Extract changelog for this version + id: changelog + run: | + # Extract relevant section from README changelog + VERSION="${{ steps.new_version.outputs.version }}" + + # Create a temporary changelog file + cat > /tmp/release_notes.md << 'EOF' + ## Release ${{ steps.new_version.outputs.version }} + + ### Changes in this release + + This release includes updates and improvements to the Linux Process Information Kernel Module. + + See the [full changelog](https://github.com/${{ github.repository }}/blob/main/README.md#changelog) for details. + EOF + + # If there's a PR description, add it + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + echo "" >> /tmp/release_notes.md + echo "### Pull Request" >> /tmp/release_notes.md + echo "${{ github.event.pull_request.title }}" >> /tmp/release_notes.md + echo "" >> /tmp/release_notes.md + echo "${{ github.event.pull_request.body }}" >> /tmp/release_notes.md + fi + + cat /tmp/release_notes.md + + - name: Update version in README + run: | + VERSION="${{ steps.new_version.outputs.version }}" + DATE=$(date +"%Y-%m-%d") + + # Add new version to changelog in README + if grep -q "## Changelog" README.md; then + # Insert new version after "## Changelog" line + sed -i "/## Changelog/a\\ +\\ +### Version $VERSION ($DATE)\\ +- Release created from ${{ github.event_name }}\\ +- Version bump: ${{ steps.version_type.outputs.type }}" README.md + + echo "Updated README.md with version $VERSION" + git add README.md + git commit -m "chore: bump version to $VERSION" || echo "No changes to commit" + fi + + - name: Create and push tag + run: | + TAG="${{ steps.new_version.outputs.tag }}" + git tag -a "$TAG" -m "Release $TAG" + git push origin "$TAG" + + - name: Create GitHub Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.new_version.outputs.tag }} + release_name: Release ${{ steps.new_version.outputs.tag }} + body_path: /tmp/release_notes.md + draft: false + prerelease: false + + - name: Push version update + if: success() + run: | + git push origin main || echo "No changes to push" diff --git a/README.md b/README.md index 9012cea..b9d2679 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ See [docs/TESTING.md](docs/TESTING.md) for detailed testing documentation. - [TECHNICAL.md](docs/TECHNICAL.md) - Kernel module details, memory layout, limitations - [CODE_QUALITY.md](docs/CODE_QUALITY.md) - Static analysis, code formatting, best practices - [SCRIPTS.md](docs/SCRIPTS.md) - Detailed script documentation +- [RELEASE.md](docs/RELEASE.md) - Version release process and guidelines ## Important Notes diff --git a/docs/RELEASE.md b/docs/RELEASE.md new file mode 100644 index 0000000..bdaa25b --- /dev/null +++ b/docs/RELEASE.md @@ -0,0 +1,183 @@ +# Release Process + +This document describes how to create new releases of the kernel module project. + +## Overview + +The project uses an automated release workflow that supports semantic versioning with three types of version bumps: + +- **Major** (x.0.0): Breaking changes or major new features +- **Minor** (1.x.0): New features, backward compatible +- **Patch** (1.3.x): Bug fixes and minor improvements + +## Release Methods + +### Method 1: Pull Request Labels (Recommended) + +When merging a pull request to `main`, add one of these labels to trigger an automatic release: + +- `release:major` - Bumps major version (e.g., 1.3.0 → 2.0.0) +- `release:minor` - Bumps minor version (e.g., 1.3.0 → 1.4.0) +- `release:patch` - Bumps patch version (e.g., 1.3.0 → 1.3.1) + +The workflow will automatically: +1. Determine the new version number +2. Update the changelog in README.md +3. Create a git tag +4. Create a GitHub release with release notes + +### Method 2: Manual Workflow Dispatch + +You can manually trigger a release from the GitHub Actions tab: + +1. Go to **Actions** → **Release** workflow +2. Click **Run workflow** +3. Select the branch (usually `main`) +4. Choose the version bump type (major/minor/patch) +5. Click **Run workflow** + +## What Happens During a Release + +1. **Version Calculation**: The workflow reads the latest git tag and calculates the new version based on the bump type +2. **Changelog Update**: Adds an entry to the README.md changelog section +3. **Git Tag Creation**: Creates an annotated git tag (e.g., `v1.4.0`) +4. **GitHub Release**: Creates a release on GitHub with auto-generated release notes +5. **Version Commit**: Pushes the updated README.md back to the repository + +## Version Numbering + +The project follows [Semantic Versioning 2.0.0](https://semver.org/): + +``` +MAJOR.MINOR.PATCH + +1.4.2 +│ │ └─ Patch: Bug fixes, typos, documentation updates +│ └─── Minor: New features, backward compatible changes +└───── Major: Breaking changes, major rewrites +``` + +### Guidelines + +**Use MAJOR version when:** +- Changing kernel module API +- Removing features or fields from /proc/elf_det/ +- Incompatible changes to output format + +**Use MINOR version when:** +- Adding new information fields to the output +- Adding new helper functions (backward compatible) +- Adding new documentation or test infrastructure + +**Use PATCH version when:** +- Fixing bugs in existing functionality +- Updating documentation +- Code formatting or refactoring +- Dependency updates + +## Current Version + +The current version can be found by: + +```bash +# Check the latest git tag +git describe --tags --abbrev=0 + +# Or check the README.md changelog +grep "### Version" README.md | head -n1 +``` + +## Example Workflows + +### Example 1: Bug Fix Release + +```bash +# Create a PR with bug fixes +git checkout -b fix/heap-calculation +# ... make changes ... +git commit -m "fix: correct heap calculation for edge cases" +git push origin fix/heap-calculation + +# Create PR and add label: release:patch +# When merged, automatically releases v1.3.1 +``` + +### Example 2: New Feature Release + +```bash +# Create a PR with new feature +git checkout -b feature/add-thread-info +# ... implement feature ... +git commit -m "feat: add thread count to process info" +git push origin feature/add-thread-info + +# Create PR and add label: release:minor +# When merged, automatically releases v1.4.0 +``` + +### Example 3: Breaking Change Release + +```bash +# Create a PR with breaking changes +git checkout -b refactor/new-output-format +# ... make breaking changes ... +git commit -m "refactor!: change output format to JSON" +git push origin refactor/new-output-format + +# Create PR and add label: release:major +# When merged, automatically releases v2.0.0 +``` + +## Troubleshooting + +### Release didn't trigger + +**Check:** +- PR was merged to `main` branch +- PR has one of the release labels (`release:major`, `release:minor`, `release:patch`) +- GitHub Actions are enabled in repository settings + +### Version number is wrong + +The workflow uses `git describe --tags --abbrev=0` to find the latest version. If this fails: + +```bash +# Check existing tags +git tag -l + +# Manually create a version tag if needed +git tag -a v1.3.0 -m "Current version" +git push origin v1.3.0 +``` + +### Permission errors + +The workflow needs `contents: write` permissions. Check: +- Repository settings → Actions → General → Workflow permissions +- Ensure "Read and write permissions" is enabled + +## Manual Release (Without Workflow) + +If you need to create a release manually: + +```bash +# Update version in README.md +vim README.md # Add changelog entry + +# Commit changes +git add README.md +git commit -m "chore: release v1.4.0" + +# Create and push tag +git tag -a v1.4.0 -m "Release v1.4.0" +git push origin main +git push origin v1.4.0 + +# Create GitHub release manually through web interface +``` + +## See Also + +- [Semantic Versioning Specification](https://semver.org/) +- [GitHub Actions Documentation](https://docs.github.com/en/actions) +- [Conventional Commits](https://www.conventionalcommits.org/) (recommended for commit messages)