From d9d0966e1f4bea49232470eac28b84327486f055 Mon Sep 17 00:00:00 2001 From: navidpadid Date: Sun, 4 Jan 2026 10:10:42 +0000 Subject: [PATCH 1/3] added the static analysis stuff and formatted code --- .clang-format | 21 +++ .cppcheck-suppressions | 7 + .devcontainer/Dockerfile | 3 + .devcontainer/devcontainer.json | 2 +- .editorconfig | 31 ++++ .github/workflows/ci.yml | 49 ++++- .gitignore | 6 + Makefile | 96 +++++++++- README.md | 319 ++++++++++++++++++++++++++++---- scripts/README.md | 69 ++++++- scripts/pre-commit.sh | 88 +++++++++ src/elf_det.c | 167 +++++++++-------- src/elf_det_tests.c | 31 ++-- src/elf_helpers.h | 27 +-- src/proc_elf_ctrl.c | 138 +++++++------- src/proc_elf_ctrl_tests.c | 27 +-- src/user_helpers.h | 16 +- 17 files changed, 860 insertions(+), 237 deletions(-) create mode 100644 .clang-format create mode 100644 .cppcheck-suppressions create mode 100644 .editorconfig create mode 100755 scripts/pre-commit.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..961acec --- /dev/null +++ b/.clang-format @@ -0,0 +1,21 @@ +# clang-format configuration for Linux kernel code +# Based on Linux kernel coding style +--- +BasedOnStyle: LLVM +IndentWidth: 8 +UseTab: Always +TabWidth: 8 +BreakBeforeBraces: Linux +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +IndentCaseLabels: false +SortIncludes: false +AlignConsecutiveMacros: true +AlignConsecutiveAssignments: false +AlignTrailingComments: false +ColumnLimit: 80 +MaxEmptyLinesToKeep: 1 +KeepEmptyLinesAtTheStartOfBlocks: false +SpaceAfterCStyleCast: false +PointerAlignment: Right diff --git a/.cppcheck-suppressions b/.cppcheck-suppressions new file mode 100644 index 0000000..931d26f --- /dev/null +++ b/.cppcheck-suppressions @@ -0,0 +1,7 @@ +# Cppcheck suppressions for kernel module code +# Suppress warnings that are false positives or not applicable to kernel code + +# Kernel-specific suppressions +missingIncludeSystem +unusedFunction:*test*.c +unmatchedSuppression diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index cf641fc..481e573 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -25,6 +25,9 @@ RUN apt-get update && apt-get install -y \ bc \ libelf-dev \ libssl-dev \ + clang-format \ + sparse \ + cppcheck \ && rm -rf /var/lib/apt/lists/* # Ensure ubuntu user exists and has sudo privileges diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 46f84a3..6d0ca4c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,7 +13,7 @@ "source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/ubuntu/.ssh,type=bind,consistency=cached" ], "features": {}, - "postCreateCommand": "bash -lc 'make --version && gcc --version'", + "postCreateCommand": "bash -c 'echo \"Setting up development environment...\" && make --version && gcc --version && clang-format --version && echo \"Installing Git hooks...\" && mkdir -p .git/hooks && if [ -f scripts/pre-commit.sh ]; then cp scripts/pre-commit.sh .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit && echo \"✓ Git pre-commit hook installed\"; fi && echo \"✓ Dev environment ready!\"'", "customizations": { "vscode": { "extensions": [ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ed4d96a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,31 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 + +# Kernel C source files +[*.{c,h}] +indent_style = tab +indent_size = 8 +trim_trailing_whitespace = true + +# Makefile +[Makefile] +indent_style = tab + +# YAML files +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +# Markdown files +[*.md] +trim_trailing_whitespace = false +indent_style = space +indent_size = 2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d4472d..fa8773f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,10 +45,51 @@ jobs: name: kernel-module-build path: build/ retention-days: 30 + + static-analysis: + name: Static Analysis and Code Quality + runs-on: ubuntu-24.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 - - name: Static analysis with sparse (if available) + - name: Install analysis tools run: | - sudo apt-get install -y sparse || true - make clean - make module C=1 || echo "Sparse analysis completed with warnings" + sudo apt-get update + sudo apt-get install -y \ + clang-format \ + cppcheck \ + sparse \ + linux-headers-$(uname -r) + + - name: Check code formatting + run: make format-check + + - name: Run checkpatch (kernel coding style) + run: make checkpatch continue-on-error: true + + - name: Run cppcheck + run: make cppcheck + continue-on-error: true + + - name: Run sparse analyzer + run: make sparse + continue-on-error: true + + unit-tests: + name: Unit Tests + runs-on: ubuntu-24.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install build tools + run: | + sudo apt-get update + sudo apt-get install -y build-essential gcc + + - name: Run unit tests + run: make unit diff --git a/.gitignore b/.gitignore index cfb1f31..cc8b1ad 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,9 @@ core.* # QEMU testing environment scripts/qemu-env/ *~ + +# Static analysis output +*.log +cppcheck-build/ +scan-build-*/ +compile_commands.json diff --git a/Makefile b/Makefile index 0677ccb..e4fca9f 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ SRC_DIR := src # Build directory for user program BUILD_DIR := build -.PHONY: all clean module user install uninstall test help unit +.PHONY: all clean module user install uninstall test help unit check format checkpatch sparse cppcheck # Default target all: module user @@ -77,17 +77,111 @@ clean: rm -rf $(SRC_DIR)/.tmp_versions @echo "Clean complete!" +# Static Analysis and Code Quality Checks + +# Run all code quality checks +check: checkpatch sparse cppcheck + @echo "" + @echo "================================================" + @echo "All static analysis checks completed!" + @echo "================================================" + +# Check kernel coding style with checkpatch.pl +checkpatch: + @echo "Running checkpatch.pl (kernel coding style)..." + @if [ -f /lib/modules/$(shell uname -r)/build/scripts/checkpatch.pl ]; then \ + for file in $(SRC_DIR)/*.c $(SRC_DIR)/*.h; do \ + if [ -f "$$file" ]; then \ + echo "Checking $$file..."; \ + /lib/modules/$(shell uname -r)/build/scripts/checkpatch.pl --no-tree --strict --file $$file || true; \ + fi \ + done; \ + else \ + echo "checkpatch.pl not found. Install kernel sources."; \ + fi + +# Run sparse static analyzer +sparse: + @echo "Running sparse static analyzer..." + @if command -v sparse >/dev/null 2>&1; then \ + $(MAKE) -C $(KDIR) M=$(PWD)/$(SRC_DIR) C=2 CF="-D__CHECK_ENDIAN__" modules || true; \ + else \ + echo "sparse not found. Install with: sudo apt-get install sparse"; \ + fi + +# Run cppcheck static analyzer +cppcheck: + @echo "Running cppcheck static analyzer..." + @if command -v cppcheck >/dev/null 2>&1; then \ + cppcheck --enable=all --inconclusive --force \ + --suppressions-list=.cppcheck-suppressions \ + --inline-suppr \ + -I$(SRC_DIR) \ + -I/lib/modules/$(shell uname -r)/build/include \ + --error-exitcode=0 \ + $(SRC_DIR)/*.c 2>&1 | grep -v "Cppcheck cannot find" || true; \ + else \ + echo "cppcheck not found. Install with: sudo apt-get install cppcheck"; \ + fi + +# Format code with clang-format +format: + @echo "Formatting code with clang-format..." + @if command -v clang-format >/dev/null 2>&1; then \ + for file in $(SRC_DIR)/*.c $(SRC_DIR)/*.h; do \ + if [ -f "$$file" ]; then \ + echo "Formatting $$file..."; \ + clang-format -i $$file; \ + fi \ + done; \ + echo "Code formatting complete!"; \ + else \ + echo "clang-format not found. Install with: sudo apt-get install clang-format"; \ + fi + +# Check if code is properly formatted (CI-friendly) +format-check: + @echo "Checking code formatting..." + @if command -v clang-format >/dev/null 2>&1; then \ + UNFORMATTED=$$(for file in $(SRC_DIR)/*.c $(SRC_DIR)/*.h; do \ + if [ -f "$$file" ]; then \ + clang-format -output-replacements-xml $$file | grep -q " 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 @@ -324,6 +570,13 @@ Contributions, issues, and feature requests are welcome! ## Changelog +### 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 diff --git a/scripts/README.md b/scripts/README.md index 08ddc4b..e52699d 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,13 +1,18 @@ -# QEMU Testing Scripts +# Testing Scripts -Scripts for safely testing the Linux Process Information Kernel Module in an isolated QEMU virtual machine. +Scripts for testing the Linux Process Information Kernel Module in isolated QEMU virtual machines. ## Overview -These scripts provide a complete QEMU-based testing environment that isolates kernel module testing from your host system. This is the recommended approach for testing kernel modules as it prevents potential system crashes or instability from affecting your development machine. +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 @@ -21,7 +26,9 @@ These scripts provide a complete QEMU-based testing environment that isolates ke ## Script Descriptions -### `qemu-setup.sh` +### QEMU Testing Scripts + +#### `qemu-setup.sh` - Downloads Ubuntu 24.04 cloud image - Creates cloud-init configuration - Sets up VM with kernel headers pre-installed @@ -32,7 +39,7 @@ These scripts provide a complete QEMU-based testing environment that isolates ke - `qemu-img` - `cloud-localds` (from cloud-image-utils package) -### `qemu-run.sh` +#### `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 @@ -43,7 +50,7 @@ These scripts provide a complete QEMU-based testing environment that isolates ke - Password: `ubuntu` - Exit QEMU: Press `Ctrl+A` then `X` -### `qemu-test.sh` +#### `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 @@ -55,11 +62,59 @@ These scripts provide a complete QEMU-based testing environment that isolates ke - VM must be running (`qemu-run.sh`) - SSH must be accessible on port 2222 -### `quick-reference.sh` +#### `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: diff --git a/scripts/pre-commit.sh b/scripts/pre-commit.sh new file mode 100755 index 0000000..865b312 --- /dev/null +++ b/scripts/pre-commit.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# Pre-commit hook to run code quality checks +# Automatically installed in dev container on startup + +set -e + +echo "Running pre-commit checks..." +echo "" + +# Check if analysis tools are installed +check_tool() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "Warning: $1 not found. Please use the dev container for development." + return 1 + fi + return 0 +} + +# Array to track failures +FAILED=0 + +# Run clang-format check +if check_tool clang-format; then + echo "Checking code formatting..." + if ! make format-check >/dev/null 2>&1; then + echo "❌ Code formatting check failed!" + echo " Run 'make format' to fix formatting issues" + FAILED=1 + else + echo "✓ Code formatting check passed" + fi +else + echo "⚠ Skipping format check (clang-format not installed)" +fi + +echo "" + +# Run cppcheck +if check_tool cppcheck; then + echo "Running cppcheck..." + if make cppcheck 2>&1 | grep -q "error:"; then + echo "⚠ Cppcheck found potential issues" + FAILED=1 + else + echo "✓ Cppcheck passed" + fi +else + echo "⚠ Skipping cppcheck (not installed)" +fi + +echo "" + +# Run checkpatch if available +if [ -f /lib/modules/$(uname -r)/build/scripts/checkpatch.pl ]; then + echo "Running checkpatch..." + # Get list of staged .c and .h files + STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(c|h)$' || true) + + if [ -n "$STAGED_FILES" ]; then + for file in $STAGED_FILES; do + if [ -f "$file" ]; then + if /lib/modules/$(uname -r)/build/scripts/checkpatch.pl --no-tree --file "$file" 2>&1 | grep -q "ERROR:"; then + echo "⚠ Checkpatch found errors in $file" + FAILED=1 + fi + fi + done + if [ $FAILED -eq 0 ]; then + echo "✓ Checkpatch passed" + fi + fi +else + echo "⚠ Skipping checkpatch (kernel sources not found)" +fi + +echo "" +echo "================================================" + +if [ $FAILED -eq 1 ]; then + echo "❌ Pre-commit checks failed!" + echo "" + echo "Fix the issues or use 'git commit --no-verify' to skip checks" + exit 1 +else + echo "✓ All pre-commit checks passed!" +fi + +exit 0 diff --git a/src/elf_det.c b/src/elf_det.c index 7cf921d..2c8cf51 100644 --- a/src/elf_det.c +++ b/src/elf_det.c @@ -1,4 +1,4 @@ -#include +#include #include //for module programming #include //for task_struct #include //for file_operations write and read @@ -6,54 +6,56 @@ #include #include //for using proc #include // for using seq operations -#include //for using file_operations +#include //for using file_operations #include //for using vm_area struct -#include //for mm_struct and VMA access -#include //for user to kernel and vice versa access +#include //for mm_struct and VMA access +#include //for user to kernel and vice versa access #include //for string libs #include //for task iteration #include //for task_cputime #include "elf_helpers.h" -MODULE_LICENSE("Dual BSD/GPL"); //module license +MODULE_LICENSE("Dual BSD/GPL"); // module license +static char buff[20] = + "1"; // the common(global) buffer between kernel and user space +static int user_pid; // the desired pid that we get from user +static int numberOpens = 0; // number of opens(writes) to the pid file -static char buff[20]="1"; //the common(global) buffer between kernel and user space -static int user_pid; //the desired pid that we get from user -static int numberOpens = 0; //number of opens(writes) to the pid file - -//skip these instances (will be described bellow) +// skip these instances (will be described bellow) static struct proc_dir_entry *elfdet_dir, *elfdet_det_entry, *elfdet_pid_entry; static int procfile_open(struct inode *inode, struct file *file); -static ssize_t procfile_read(struct file*, char*, size_t, loff_t*); -static ssize_t procfile_write(struct file*, const char*, size_t, loff_t*); - +static ssize_t procfile_read(struct file *, char *, size_t, loff_t *); +static ssize_t procfile_write(struct file *, const char *, size_t, loff_t *); -//det proc file_operations starts +// det proc file_operations starts -//this function is the base function to gather information from kernel -static int elfdet_show(struct seq_file *m, void *v) { +// this function is the base function to gather information from kernel +static int elfdet_show(struct seq_file *m, void *v) +{ struct task_struct *task; unsigned long bss_start = 0, bss_end = 0; unsigned long elf_header = 0; u64 delta_ns, total_ns; u64 usage_permyriad; // CPU usage in hundredths of a percent (X.XX%) - - sscanf(buff, "%d", &user_pid); //type cast pid from user(buff) to integer - task = pid_task(find_vpid(user_pid), PIDTYPE_PID); //get the task from pid + sscanf(buff, "%d", + &user_pid); // type cast pid from user(buff) to integer + task = + pid_task(find_vpid(user_pid), PIDTYPE_PID); // get the task from pid if (!task || !task->mm) { seq_printf(m, "Invalid PID or process has no memory context\n"); return 0; } - /* CPU usage: total CPU time of task since start divided by elapsed wall time */ + /* CPU usage: total CPU time of task since start divided by elapsed wall + * time */ total_ns = (u64)task->utime + (u64)task->stime; delta_ns = ktime_get_ns() - task->start_time; usage_permyriad = compute_usage_permyriad(total_ns, delta_ns); - + // Access VMA using VMA iterator for kernel 6.8+ if (mmap_read_lock_killable(task->mm)) { seq_printf(m, "Failed to lock mm\n"); @@ -62,110 +64,123 @@ static int elfdet_show(struct seq_file *m, void *v) { /* Use mm fields directly for ELF and BSS */ elf_header = task->mm->start_code; - compute_bss_range(task->mm->end_data, task->mm->start_brk, &bss_start, &bss_end); + compute_bss_range(task->mm->end_data, task->mm->start_brk, &bss_start, + &bss_end); mmap_read_unlock(task->mm); - //now print the information we want to the det file - seq_printf(m, "PID \tNAME \tCPU(%%) \tSTART_CODE \tEND_CODE \tSTART_DATA\tEND_DATA \tBSS_START\tBSS_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", - 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); + // now print the information we want to the det file + seq_printf(m, "PID \tNAME \tCPU(%%) \tSTART_CODE \tEND_CODE " + "\tSTART_DATA\tEND_DATA \tBSS_START\tBSS_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", + 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); return 0; } -//runs when openning file -static int elfdet_open(struct inode *inode, struct file *file) { - return single_open(file, elfdet_show, NULL); //calling elfdet_show +// runs when openning file +static int elfdet_open(struct inode *inode, struct file *file) +{ + return single_open(file, elfdet_show, NULL); // calling elfdet_show } -//file operations of det proc (using proc_ops for kernel 5.6+) +// file operations of det proc (using proc_ops for kernel 5.6+) static const struct proc_ops elfdet_det_ops = { - .proc_open = elfdet_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = single_release, + .proc_open = elfdet_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, }; +// elf proc file_operations starts - - -//elf proc file_operations starts - -//runs when elf opens -//will be called every time this file is accessed shows number of accessed times -static int procfile_open(struct inode *inode, struct file *file) +// runs when elf opens +// will be called every time this file is accessed shows number of accessed +// times +static int procfile_open(struct inode *inode, struct file *file) { numberOpens++; printk(KERN_INFO "procfile opened %d times", numberOpens); return 0; } -//when we cat elf file this function will be runned (this is useless here) because our info is in det file not here! -static ssize_t procfile_read(struct file *file, char *buffer, size_t length, loff_t *offset) +// when we cat elf file this function will be runned (this is useless here) +// because our info is in det file not here! +static ssize_t procfile_read(struct file *file, char *buffer, size_t length, + loff_t *offset) { - static int finished = 0; //normal return value other than '0' will cause loop - int ret = 0; + static int finished = + 0; // normal return value other than '0' will cause loop + int ret = 0; - printk(KERN_INFO "procfile read called\n"); + printk(KERN_INFO "procfile read called\n"); - if (finished) { - printk(KERN_INFO "procfs read: END\n"); - finished = 0; - return 0; - } + if (finished) { + printk(KERN_INFO "procfs read: END\n"); + finished = 0; + return 0; + } - finished = 1; - ret = sprintf(buffer, "buff variable : %s\n", buff); - return ret; + finished = 1; + ret = sprintf(buffer, "buff variable : %s\n", buff); + return ret; } -//most important function of elf! called when we write some charachters into it -static ssize_t procfile_write(struct file *file, const char *buffer, size_t length, loff_t *offset) +// most important function of elf! called when we write some charachters into it +static ssize_t procfile_write(struct file *file, const char *buffer, + size_t length, loff_t *offset) { long ret; - ret = strncpy_from_user(buff, buffer, sizeof(buff) - 1); //copy the charachters to buff (global buffer, inorder to use it in kernel) + ret = strncpy_from_user(buff, buffer, + sizeof(buff) - + 1); // copy the charachters to buff (global + // buffer, inorder to use it in kernel) if (ret < 0) return ret; buff[ret] = '\0'; // Null terminate - printk(KERN_INFO "procfs_write called\n"); + printk(KERN_INFO "procfs_write called\n"); return length; } - -static const struct proc_ops write_pops = { +static const struct proc_ops write_pops = { .proc_open = procfile_open, .proc_read = procfile_read, - .proc_write = procfile_write,//this is the important part + .proc_write = procfile_write, // this is the important part }; - -static int elfdet_init(void) { - elfdet_dir = proc_mkdir("elf_det", NULL); //creating the directory: elf_det in proc +static int elfdet_init(void) +{ + elfdet_dir = proc_mkdir( + "elf_det", NULL); // creating the directory: elf_det in proc if (!elfdet_dir) { return -ENOMEM; - } - //0777 means full premmisions for the file - elfdet_det_entry = proc_create("det", 0777, elfdet_dir, &elfdet_det_ops); //create proc file det with elfdet_det_ops + } + // 0777 means full premmisions for the file + elfdet_det_entry = proc_create( + "det", 0777, elfdet_dir, + &elfdet_det_ops); // create proc file det with elfdet_det_ops printk("det initiated; /proc/elf_det/det created\n"); - elfdet_pid_entry = proc_create("pid", 0777, elfdet_dir, &write_pops); //create proc file pid with write_pops + elfdet_pid_entry = + proc_create("pid", 0777, elfdet_dir, + &write_pops); // create proc file pid with write_pops printk("pid initiated; /proc/elf_det/pid created\n"); if (!elfdet_det_entry) { return -ENOMEM; } - return 0; } -//the remove operations done by module(cleaning up) -static void elfdet_exit(void) { +// the remove operations done by module(cleaning up) +static void elfdet_exit(void) +{ proc_remove(elfdet_det_entry); printk("elf_det exited; /proc/elf_det/det deleted\n"); proc_remove(elfdet_pid_entry); @@ -173,6 +188,6 @@ static void elfdet_exit(void) { proc_remove(elfdet_dir); } -//macros for init and exit +// macros for init and exit module_init(elfdet_init); module_exit(elfdet_exit); diff --git a/src/elf_det_tests.c b/src/elf_det_tests.c index 101de92..cd6bd60 100644 --- a/src/elf_det_tests.c +++ b/src/elf_det_tests.c @@ -2,22 +2,23 @@ #include #include -int main(void) { - /* compute_usage_permyriad tests */ - assert(compute_usage_permyriad(0, 1000000ULL) == 0); - assert(compute_usage_permyriad(500000ULL, 1000000ULL) == 5000ULL); - assert(compute_usage_permyriad(250000ULL, 1000000ULL) == 2500ULL); - assert(compute_usage_permyriad(1000000ULL, 1000000ULL) == 10000ULL); - assert(compute_usage_permyriad(0, 0) == 0); +int main(void) +{ + /* compute_usage_permyriad tests */ + assert(compute_usage_permyriad(0, 1000000ULL) == 0); + assert(compute_usage_permyriad(500000ULL, 1000000ULL) == 5000ULL); + assert(compute_usage_permyriad(250000ULL, 1000000ULL) == 2500ULL); + assert(compute_usage_permyriad(1000000ULL, 1000000ULL) == 10000ULL); + assert(compute_usage_permyriad(0, 0) == 0); - /* compute_bss_range tests */ - unsigned long s = 0, e = 0; - assert(compute_bss_range(1000UL, 2000UL, &s, &e) == 1); - assert(s == 1000UL && e == 2000UL); + /* compute_bss_range tests */ + unsigned long s = 0, e = 0; + assert(compute_bss_range(1000UL, 2000UL, &s, &e) == 1); + assert(s == 1000UL && e == 2000UL); - assert(compute_bss_range(3000UL, 2000UL, &s, &e) == 0); - assert(s == 0UL && e == 0UL); + assert(compute_bss_range(3000UL, 2000UL, &s, &e) == 0); + assert(s == 0UL && e == 0UL); - puts("elf_helpers tests passed"); - return 0; + puts("elf_helpers tests passed"); + return 0; } \ No newline at end of file diff --git a/src/elf_helpers.h b/src/elf_helpers.h index 2cdbd57..99dc9a0 100644 --- a/src/elf_helpers.h +++ b/src/elf_helpers.h @@ -11,22 +11,23 @@ typedef uint64_t eh_u64; /* Compute CPU usage permyriad (percent * 100) from total_ns and delta_ns */ static inline eh_u64 compute_usage_permyriad(eh_u64 total_ns, eh_u64 delta_ns) { - if (delta_ns == 0) return 0; - return (10000ULL * total_ns) / delta_ns; + if (delta_ns == 0) + return 0; + return (10000ULL * total_ns) / delta_ns; } /* Compute BSS range from end_data and start_brk; returns 0 on invalid */ static inline int compute_bss_range(unsigned long end_data, - unsigned long start_brk, - unsigned long *out_start, - unsigned long *out_end) + unsigned long start_brk, + unsigned long *out_start, + unsigned long *out_end) { - if (start_brk < end_data) { - *out_start = 0; - *out_end = 0; - return 0; - } - *out_start = end_data; - *out_end = start_brk; - return 1; + if (start_brk < end_data) { + *out_start = 0; + *out_end = 0; + return 0; + } + *out_start = end_data; + *out_end = start_brk; + return 1; } diff --git a/src/proc_elf_ctrl.c b/src/proc_elf_ctrl.c index b6167fd..11ced70 100644 --- a/src/proc_elf_ctrl.c +++ b/src/proc_elf_ctrl.c @@ -6,77 +6,81 @@ int main(int argc, char **argv) { - FILE *fp; - char pid_user[20]; - char buff[2048]; + FILE *fp; + char pid_user[20]; + char buff[2048]; - if (argc > 1) { - strncpy(pid_user, argv[1], sizeof(pid_user) - 1); - pid_user[sizeof(pid_user) - 1] = '\0'; + if (argc > 1) { + strncpy(pid_user, argv[1], sizeof(pid_user) - 1); + pid_user[sizeof(pid_user) - 1] = '\0'; - char *pid_path = build_proc_path("pid"); - fp = fopen(pid_path, "w"); - if (!fp) { - perror("open pid"); - free(pid_path); - return 1; - } - fprintf(fp,"%s", pid_user); - fclose(fp); - free(pid_path); + char *pid_path = build_proc_path("pid"); + fp = fopen(pid_path, "w"); + if (!fp) { + perror("open pid"); + free(pid_path); + return 1; + } + fprintf(fp, "%s", pid_user); + fclose(fp); + free(pid_path); - char *det_path = build_proc_path("det"); - fp = fopen(det_path, "r"); - if (!fp) { - perror("open det"); - free(det_path); - return 1; - } - if (fgets(buff, sizeof(buff), fp)) - printf("%s\n", buff); - if (fgets(buff, sizeof(buff), fp)) - printf("%s\n", buff); - fclose(fp); - free(det_path); - return 0; - } + char *det_path = build_proc_path("det"); + fp = fopen(det_path, "r"); + if (!fp) { + perror("open det"); + free(det_path); + return 1; + } + if (fgets(buff, sizeof(buff), fp)) + printf("%s\n", buff); + if (fgets(buff, sizeof(buff), fp)) + printf("%s\n", buff); + fclose(fp); + free(det_path); + return 0; + } - printf("***************************************************************************\n"); - printf("******Navid user program for gathering memory info on desired process******\n"); - printf("***************************************************************************\n"); - printf("***************************************************************************\n"); - while (1) { - printf("************enter the process id:"); - if (scanf("%19s", pid_user) != 1) { - fprintf(stderr, "invalid input\n"); - break; - } + printf("***************************************************************" + "************\n"); + printf("******Navid user program for gathering memory info on desired " + "process******\n"); + printf("***************************************************************" + "************\n"); + printf("***************************************************************" + "************\n"); + while (1) { + printf("************enter the process id:"); + if (scanf("%19s", pid_user) != 1) { + fprintf(stderr, "invalid input\n"); + break; + } - char *pid_path2 = build_proc_path("pid"); - fp = fopen(pid_path2, "w"); - if (!fp) { - perror("open pid"); - free(pid_path2); - return 1; - } - fprintf(fp,"%s", pid_user); - fclose(fp); - free(pid_path2); + char *pid_path2 = build_proc_path("pid"); + fp = fopen(pid_path2, "w"); + if (!fp) { + perror("open pid"); + free(pid_path2); + return 1; + } + fprintf(fp, "%s", pid_user); + fclose(fp); + free(pid_path2); - printf("the process info is here:\n"); - char *det_path2 = build_proc_path("det"); - fp = fopen(det_path2, "r"); - if (!fp) { - perror("open det"); - free(det_path2); - return 1; - } - if (fgets(buff, sizeof(buff), fp)) - printf("%s\n", buff); - if (fgets(buff, sizeof(buff), fp)) - printf("%s\n", buff); - fclose(fp); - free(det_path2); - } - return 0; + printf("the process info is here:\n"); + char *det_path2 = build_proc_path("det"); + fp = fopen(det_path2, "r"); + if (!fp) { + perror("open det"); + free(det_path2); + return 1; + } + if (fgets(buff, sizeof(buff), fp)) + printf("%s\n", buff); + if (fgets(buff, sizeof(buff), fp)) + printf("%s\n", buff); + fclose(fp); + free(det_path2); + } + return 0; } \ No newline at end of file diff --git a/src/proc_elf_ctrl_tests.c b/src/proc_elf_ctrl_tests.c index bfe46e1..02a9981 100644 --- a/src/proc_elf_ctrl_tests.c +++ b/src/proc_elf_ctrl_tests.c @@ -3,19 +3,20 @@ #include #include -int main(void) { - /* Without env override */ - unsetenv("ELF_DET_PROC_DIR"); - char *p1 = build_proc_path("pid"); - assert(p1 && strcmp(p1, "/proc/elf_det/pid") == 0); - free(p1); +int main(void) +{ + /* Without env override */ + unsetenv("ELF_DET_PROC_DIR"); + char *p1 = build_proc_path("pid"); + assert(p1 && strcmp(p1, "/proc/elf_det/pid") == 0); + free(p1); - /* With env override */ - setenv("ELF_DET_PROC_DIR", "/tmp/fakeproc", 1); - char *p2 = build_proc_path("det"); - assert(p2 && strcmp(p2, "/tmp/fakeproc/det") == 0); - free(p2); + /* With env override */ + setenv("ELF_DET_PROC_DIR", "/tmp/fakeproc", 1); + char *p2 = build_proc_path("det"); + assert(p2 && strcmp(p2, "/tmp/fakeproc/det") == 0); + free(p2); - puts("user_helpers tests passed"); - return 0; + puts("user_helpers tests passed"); + return 0; } \ No newline at end of file diff --git a/src/user_helpers.h b/src/user_helpers.h index 43c37ac..2d03f88 100644 --- a/src/user_helpers.h +++ b/src/user_helpers.h @@ -7,12 +7,14 @@ /* Build path to /proc/elf_det/ with optional override via env. */ static inline char *build_proc_path(const char *name) { - const char *base = getenv("ELF_DET_PROC_DIR"); - if (!base || !*base) base = "/proc/elf_det"; + const char *base = getenv("ELF_DET_PROC_DIR"); + if (!base || !*base) + base = "/proc/elf_det"; - size_t len = strlen(base) + 1 + strlen(name) + 1; - char *p = (char *)malloc(len); - if (!p) return NULL; - snprintf(p, len, "%s/%s", base, name); - return p; + size_t len = strlen(base) + 1 + strlen(name) + 1; + char *p = (char *)malloc(len); + if (!p) + return NULL; + snprintf(p, len, "%s/%s", base, name); + return p; } From 1b6653780a3791ccb75313c8c5c53148e25302a8 Mon Sep 17 00:00:00 2001 From: navidpadid Date: Sun, 4 Jan 2026 10:31:08 +0000 Subject: [PATCH 2/3] fixed style and code analysis results --- .checkpatch-camelcase.git. | 0 .cppcheck-suppressions | 6 ++ Makefile | 11 ++-- src/elf_det.c | 113 +++++++++++++++++++++---------------- src/elf_det_tests.c | 11 +++- src/elf_helpers.h | 3 +- src/proc_elf_ctrl.c | 32 +++++++---- src/proc_elf_ctrl_tests.c | 10 +++- src/user_helpers.h | 3 + 9 files changed, 118 insertions(+), 71 deletions(-) create mode 100644 .checkpatch-camelcase.git. diff --git a/.checkpatch-camelcase.git. b/.checkpatch-camelcase.git. new file mode 100644 index 0000000..e69de29 diff --git a/.cppcheck-suppressions b/.cppcheck-suppressions index 931d26f..64cd289 100644 --- a/.cppcheck-suppressions +++ b/.cppcheck-suppressions @@ -5,3 +5,9 @@ missingIncludeSystem unusedFunction:*test*.c unmatchedSuppression + +# Suppress preprocessor errors in kernel headers (configuration issues) +preprocessorErrorDirective:*/linux/bitops.h +preprocessorErrorDirective:*/linux/*.h +noValidConfiguration:src/elf_det.c +noValidConfiguration:src/elf_det.mod.c diff --git a/Makefile b/Makefile index e4fca9f..c087153 100644 --- a/Makefile +++ b/Makefile @@ -91,10 +91,13 @@ checkpatch: @echo "Running checkpatch.pl (kernel coding style)..." @if [ -f /lib/modules/$(shell uname -r)/build/scripts/checkpatch.pl ]; then \ for file in $(SRC_DIR)/*.c $(SRC_DIR)/*.h; do \ - if [ -f "$$file" ]; then \ - echo "Checking $$file..."; \ - /lib/modules/$(shell uname -r)/build/scripts/checkpatch.pl --no-tree --strict --file $$file || true; \ - fi \ + case "$$file" in \ + *.mod.c) ;; \ + *) if [ -f "$$file" ]; then \ + echo "Checking $$file..."; \ + /lib/modules/$(shell uname -r)/build/scripts/checkpatch.pl --no-tree --strict --file $$file || true; \ + fi ;; \ + esac; \ done; \ else \ echo "checkpatch.pl not found. Install kernel sources."; \ diff --git a/src/elf_det.c b/src/elf_det.c index 2c8cf51..82cfb01 100644 --- a/src/elf_det.c +++ b/src/elf_det.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) #include #include //for module programming #include //for task_struct @@ -20,14 +21,15 @@ MODULE_LICENSE("Dual BSD/GPL"); // module license static char buff[20] = "1"; // the common(global) buffer between kernel and user space static int user_pid; // the desired pid that we get from user -static int numberOpens = 0; // number of opens(writes) to the pid file +static int number_opens; // number of opens(writes) to the pid file // skip these instances (will be described bellow) static struct proc_dir_entry *elfdet_dir, *elfdet_det_entry, *elfdet_pid_entry; static int procfile_open(struct inode *inode, struct file *file); -static ssize_t procfile_read(struct file *, char *, size_t, loff_t *); -static ssize_t procfile_write(struct file *, const char *, size_t, loff_t *); +static ssize_t procfile_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t procfile_write(struct file *, const char __user *, size_t, + loff_t *); // det proc file_operations starts @@ -39,26 +41,31 @@ static int elfdet_show(struct seq_file *m, void *v) unsigned long elf_header = 0; u64 delta_ns, total_ns; u64 usage_permyriad; // CPU usage in hundredths of a percent (X.XX%) + int ret; - sscanf(buff, "%d", - &user_pid); // type cast pid from user(buff) to integer - task = - pid_task(find_vpid(user_pid), PIDTYPE_PID); // get the task from pid + ret = kstrtoint(buff, 10, &user_pid); + if (ret != 0) { + seq_puts(m, "Failed to parse PID\n"); + return 0; + } + + task = pid_task(find_vpid(user_pid), PIDTYPE_PID); if (!task || !task->mm) { - seq_printf(m, "Invalid PID or process has no memory context\n"); + seq_puts(m, "Invalid PID or process has no memory context\n"); return 0; } /* CPU usage: total CPU time of task since start divided by elapsed wall - * time */ + * time + */ total_ns = (u64)task->utime + (u64)task->stime; delta_ns = ktime_get_ns() - task->start_time; usage_permyriad = compute_usage_permyriad(total_ns, delta_ns); // Access VMA using VMA iterator for kernel 6.8+ if (mmap_read_lock_killable(task->mm)) { - seq_printf(m, "Failed to lock mm\n"); + seq_puts(m, "Failed to lock mm\n"); return 0; } @@ -70,8 +77,8 @@ static int elfdet_show(struct seq_file *m, void *v) mmap_read_unlock(task->mm); // now print the information we want to the det file - seq_printf(m, "PID \tNAME \tCPU(%%) \tSTART_CODE \tEND_CODE " - "\tSTART_DATA\tEND_DATA \tBSS_START\tBSS_END\tELF\n"); + seq_puts(m, "PID \tNAME \tCPU(%) \tSTART_CODE \tEND_CODE " + "\tSTART_DATA\tEND_DATA \tBSS_START\tBSS_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", @@ -83,7 +90,7 @@ static int elfdet_show(struct seq_file *m, void *v) return 0; } -// runs when openning file +// runs when opening file static int elfdet_open(struct inode *inode, struct file *file) { return single_open(file, elfdet_show, NULL); // calling elfdet_show @@ -104,46 +111,54 @@ static const struct proc_ops elfdet_det_ops = { // times static int procfile_open(struct inode *inode, struct file *file) { - numberOpens++; - printk(KERN_INFO "procfile opened %d times", numberOpens); + number_opens++; + pr_info("procfile opened %d times\n", number_opens); return 0; } -// when we cat elf file this function will be runned (this is useless here) +// when we cat elf file this function will be run (this is useless here) // because our info is in det file not here! -static ssize_t procfile_read(struct file *file, char *buffer, size_t length, - loff_t *offset) +static ssize_t procfile_read(struct file *file, char __user *buffer, + size_t length, loff_t *offset) { - static int finished = - 0; // normal return value other than '0' will cause loop - int ret = 0; + static int finished; + char tmp[64]; + int len; - printk(KERN_INFO "procfile read called\n"); + // normal return value other than '0' will cause loop + + pr_info("procfile read called\n"); if (finished) { - printk(KERN_INFO "procfs read: END\n"); + pr_info("procfs read: END\n"); finished = 0; return 0; } finished = 1; - ret = sprintf(buffer, "buff variable : %s\n", buff); - return ret; + len = snprintf(tmp, sizeof(tmp), "buff variable : %s\n", buff); + if (len < 0) + return -EFAULT; + if (len > length) + len = length; + if (copy_to_user(buffer, tmp, len)) + return -EFAULT; + return len; } -// most important function of elf! called when we write some charachters into it -static ssize_t procfile_write(struct file *file, const char *buffer, +// most important function of elf! called when we write some characters into it +static ssize_t procfile_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) { long ret; - ret = strncpy_from_user(buff, buffer, - sizeof(buff) - - 1); // copy the charachters to buff (global - // buffer, inorder to use it in kernel) + + ret = strncpy_from_user(buff, buffer, sizeof(buff) - 1); + // copy the characters to buff (global buffer, in order to use it in + // kernel) if (ret < 0) return ret; buff[ret] = '\0'; // Null terminate - printk(KERN_INFO "procfs_write called\n"); + pr_info("procfs_write called\n"); return length; } @@ -155,25 +170,23 @@ static const struct proc_ops write_pops = { static int elfdet_init(void) { - elfdet_dir = proc_mkdir( - "elf_det", NULL); // creating the directory: elf_det in proc + elfdet_dir = proc_mkdir("elf_det", NULL); + // creating the directory: elf_det in proc - if (!elfdet_dir) { + if (!elfdet_dir) return -ENOMEM; - } - // 0777 means full premmisions for the file - elfdet_det_entry = proc_create( - "det", 0777, elfdet_dir, - &elfdet_det_ops); // create proc file det with elfdet_det_ops - printk("det initiated; /proc/elf_det/det created\n"); - elfdet_pid_entry = - proc_create("pid", 0777, elfdet_dir, - &write_pops); // create proc file pid with write_pops - printk("pid initiated; /proc/elf_det/pid created\n"); - - if (!elfdet_det_entry) { + + // 0644 means owner read/write, others read-only + elfdet_det_entry = + proc_create("det", 0644, elfdet_dir, &elfdet_det_ops); + // create proc file det with elfdet_det_ops + pr_info("det initiated; /proc/elf_det/det created\n"); + elfdet_pid_entry = proc_create("pid", 0644, elfdet_dir, &write_pops); + // create proc file pid with write_pops + pr_info("pid initiated; /proc/elf_det/pid created\n"); + + if (!elfdet_det_entry) return -ENOMEM; - } return 0; } @@ -182,9 +195,9 @@ static int elfdet_init(void) static void elfdet_exit(void) { proc_remove(elfdet_det_entry); - printk("elf_det exited; /proc/elf_det/det deleted\n"); + pr_info("elf_det exited; /proc/elf_det/det deleted\n"); proc_remove(elfdet_pid_entry); - printk("elf_det exited; /proc/elf_det/pid deleted\n"); + pr_info("elf_det exited; /proc/elf_det/pid deleted\n"); proc_remove(elfdet_dir); } diff --git a/src/elf_det_tests.c b/src/elf_det_tests.c index cd6bd60..575b86f 100644 --- a/src/elf_det_tests.c +++ b/src/elf_det_tests.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) #include "elf_helpers.h" #include #include @@ -13,12 +14,16 @@ int main(void) /* compute_bss_range tests */ unsigned long s = 0, e = 0; - assert(compute_bss_range(1000UL, 2000UL, &s, &e) == 1); + int ret1, ret2; + + ret1 = compute_bss_range(1000UL, 2000UL, &s, &e); + assert(ret1 == 1); assert(s == 1000UL && e == 2000UL); - assert(compute_bss_range(3000UL, 2000UL, &s, &e) == 0); + ret2 = compute_bss_range(3000UL, 2000UL, &s, &e); + assert(ret2 == 0); assert(s == 0UL && e == 0UL); puts("elf_helpers tests passed"); return 0; -} \ No newline at end of file +} diff --git a/src/elf_helpers.h b/src/elf_helpers.h index 99dc9a0..102fa50 100644 --- a/src/elf_helpers.h +++ b/src/elf_helpers.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ #pragma once #ifdef __KERNEL__ @@ -5,7 +6,7 @@ typedef u64 eh_u64; #else #include -typedef uint64_t eh_u64; +typedef u64 eh_u64; #endif /* Compute CPU usage permyriad (percent * 100) from total_ns and delta_ns */ diff --git a/src/proc_elf_ctrl.c b/src/proc_elf_ctrl.c index 11ced70..7d4986f 100644 --- a/src/proc_elf_ctrl.c +++ b/src/proc_elf_ctrl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) #include #include #include @@ -11,10 +12,18 @@ int main(int argc, char **argv) char buff[2048]; if (argc > 1) { - strncpy(pid_user, argv[1], sizeof(pid_user) - 1); - pid_user[sizeof(pid_user) - 1] = '\0'; + char *pid_path; + char *det_path; + size_t len; - char *pid_path = build_proc_path("pid"); + /* Safe string copy with explicit bounds checking */ + len = strlen(argv[1]); + if (len >= sizeof(pid_user)) + len = sizeof(pid_user) - 1; + memcpy(pid_user, argv[1], len); + pid_user[len] = '\0'; + + pid_path = build_proc_path("pid"); fp = fopen(pid_path, "w"); if (!fp) { perror("open pid"); @@ -25,7 +34,7 @@ int main(int argc, char **argv) fclose(fp); free(pid_path); - char *det_path = build_proc_path("det"); + det_path = build_proc_path("det"); fp = fopen(det_path, "r"); if (!fp) { perror("open det"); @@ -42,21 +51,24 @@ int main(int argc, char **argv) } printf("***************************************************************" - "************\n"); + "********\n"); printf("******Navid user program for gathering memory info on desired " "process******\n"); printf("***************************************************************" - "************\n"); + "********\n"); printf("***************************************************************" - "************\n"); + "********\n"); while (1) { + char *pid_path2; + char *det_path2; + printf("************enter the process id:"); if (scanf("%19s", pid_user) != 1) { fprintf(stderr, "invalid input\n"); break; } - char *pid_path2 = build_proc_path("pid"); + pid_path2 = build_proc_path("pid"); fp = fopen(pid_path2, "w"); if (!fp) { perror("open pid"); @@ -68,7 +80,7 @@ int main(int argc, char **argv) free(pid_path2); printf("the process info is here:\n"); - char *det_path2 = build_proc_path("det"); + det_path2 = build_proc_path("det"); fp = fopen(det_path2, "r"); if (!fp) { perror("open det"); @@ -83,4 +95,4 @@ int main(int argc, char **argv) free(det_path2); } return 0; -} \ No newline at end of file +} diff --git a/src/proc_elf_ctrl_tests.c b/src/proc_elf_ctrl_tests.c index 02a9981..1a34fa5 100644 --- a/src/proc_elf_ctrl_tests.c +++ b/src/proc_elf_ctrl_tests.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) #include "user_helpers.h" #include #include @@ -5,18 +6,21 @@ int main(void) { + char *p1; + char *p2; + /* Without env override */ unsetenv("ELF_DET_PROC_DIR"); - char *p1 = build_proc_path("pid"); + p1 = build_proc_path("pid"); assert(p1 && strcmp(p1, "/proc/elf_det/pid") == 0); free(p1); /* With env override */ setenv("ELF_DET_PROC_DIR", "/tmp/fakeproc", 1); - char *p2 = build_proc_path("det"); + p2 = build_proc_path("det"); assert(p2 && strcmp(p2, "/tmp/fakeproc/det") == 0); free(p2); puts("user_helpers tests passed"); return 0; -} \ No newline at end of file +} diff --git a/src/user_helpers.h b/src/user_helpers.h index 2d03f88..eadef5a 100644 --- a/src/user_helpers.h +++ b/src/user_helpers.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ #pragma once #include @@ -8,11 +9,13 @@ static inline char *build_proc_path(const char *name) { const char *base = getenv("ELF_DET_PROC_DIR"); + if (!base || !*base) base = "/proc/elf_det"; size_t len = strlen(base) + 1 + strlen(name) + 1; char *p = (char *)malloc(len); + if (!p) return NULL; snprintf(p, len, "%s/%s", base, name); From e987dbf180521432581eb1652da330e67d923dce Mon Sep 17 00:00:00 2001 From: navidpadid Date: Sun, 4 Jan 2026 10:35:24 +0000 Subject: [PATCH 3/3] fix tests --- src/elf_helpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elf_helpers.h b/src/elf_helpers.h index 102fa50..ac65bfa 100644 --- a/src/elf_helpers.h +++ b/src/elf_helpers.h @@ -6,7 +6,7 @@ typedef u64 eh_u64; #else #include -typedef u64 eh_u64; +typedef uint64_t eh_u64; #endif /* Compute CPU usage permyriad (percent * 100) from total_ns and delta_ns */