================================================================================
WORKSHEET: STAGE 2 - TRACING getname() IN KERNEL SPACE
================================================================================
Each step: DO something, SEE output, FILL blanks, VERIFY axioms.
No magic. No new things without derivation.

================================================================================
STEP 01: PREPARE THE TEST PROGRAM
================================================================================

DO:   Create the minimal test program.
RUN:  cat > minimal_open.c << 'EOF'
      #include <fcntl.h>
      int main() {
          int fd = open("somefile", O_RDWR);
          return 0;
      }
      EOF

RUN:  gcc minimal_open.c -o minimal_open

VERIFY:
    $ file minimal_open
    ELF 64-bit LSB pie executable, x86-64, dynamically linked

================================================================================
STEP 02: FIND KERNEL SOURCE FOR getname()
================================================================================

DO:   Locate the function definition.
RUN:  grep -rn "^struct filename \*$" /usr/src/linux-source-6.8.0/fs/ | head -5
      grep -rn "getname(" /usr/src/linux-source-6.8.0/fs/namei.c | head -5

OBSERVE:
    getname() is defined in: fs/namei.c
    At line number: _____________

DO:   View the function.
RUN:  sed -n '216,220p' /usr/src/linux-source-6.8.0/fs/namei.c

FILL:
    getname() calls which internal function? _____________
    With how many arguments? _____________


================================================================================
STEP 03: UNDERSTAND STRUCT FILENAME
================================================================================

DO:   Find the structure definition.
RUN:  grep -A 10 "^struct filename {" /usr/src/linux-source-6.8.0/include/linux/fs.h

FILL THE LAYOUT:
    +0x00: name   = _____ bytes (pointer to pathname)
    +0x08: uptr   = _____ bytes (original user pointer)
    +0x10: refcnt = _____ bytes (reference count)
    +0x14: padding= _____ bytes (alignment)
    +0x18: aname  = _____ bytes (audit)
    +0x20: iname[]= flexible array

    sizeof(struct filename) = _____ bytes

================================================================================
STEP 04: FIND SLAB CACHE SIZE
================================================================================

DO:   Check slab allocation.
RUN:  sudo cat /proc/slabinfo | grep names

OUTPUT:
    names_cache   ___   ___   ____   _   _

FILL:
    Size of each names_cache object: _____ bytes
    This equals: PATH_MAX = _____

================================================================================
STEP 05: BUILD THE KPROBE MODULE
================================================================================

DO:   Navigate to driver directory.
RUN:  cd kernel/drivers/arg2_filename

DO:   View the critical parts of trace_filename.c
      [VIEW SOURCE ON GITHUB]
RUN:  head -60 trace_filename.c

FILL THE AXIOMS FROM COMMENTS:
    Register for first argument (x86_64): _____
    Register for return value: _____
    sizeof(struct filename): _____ bytes
    offsetof(name): _____
    offsetof(uptr): _____

================================================================================
STEP 06: COMPILE THE MODULE
================================================================================

DO:   Build the kernel module.
RUN:  make

EXPECTED:
    make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
    Building modules, stage 2.
    CC [M]  trace_filename.o
    ...
    LD [M]  trace_filename.ko

VERIFY:
    $ ls -la trace_filename.ko
    Size: approximately _____ KB

FAILURE PREDICTION:
    If "no rule to make target" -> Makefile missing or wrong syntax
    If "linux/kprobes.h not found" -> kernel headers not installed

================================================================================
STEP 07: LOAD THE MODULE
================================================================================

DO:   Clear dmesg and load module.
RUN:  sudo dmesg -C
      sudo insmod trace_filename.ko

VERIFY:
    $ sudo dmesg
    ARG2: Module loaded. Probing getname(). sizeof(my_data)=_____

FILL:
    sizeof(my_data) should be: 8 + 16 + 4 = _____ bytes

================================================================================
STEP 08: RUN THE TEST PROGRAM
================================================================================

DO:   Execute minimal_open to trigger getname().
RUN:  ./minimal_open

DO:   Check trace output.
RUN:  sudo dmesg | grep "#2"

EXPECTED OUTPUT:
    #2. getname. SUCCESS.
        user_ptr (RDI saved) = 0x0000____________
        fn (RAX)             = 0xffff____________
        fn->name (+0x00)     = 0xffff____________
        fn->uptr (+0x08)     = 0x0000____________
        string               = "_________"
        [OK] AXIOM: fn->uptr == saved RDI

================================================================================
STEP 09: VERIFICATION EXERCISE
================================================================================

From your captured output, fill in:

USER POINTER:
    user_ptr = 0x____________________

KERNEL POINTER:
    fn = 0x____________________

MATH CHECK 1: Is name pointing to iname[]?
    fn + 0x20 = 0x____________________ + 0x20 = 0x____________________
    fn->name = 0x____________________
    
    Are they equal? [ YES / NO ]
    
    If YES -> Phase 1 (embedded buffer) was used
    If NO  -> Phase 2 (separate allocation) was used

MATH CHECK 2: User pointer preserved?
    saved RDI  = 0x____________________
    fn->uptr   = 0x____________________
    
    Are they equal? [ YES / NO ]
    
    If NO -> Something is wrong! Check your filter.

MATH CHECK 3: Address space boundaries
    User pointer bits 63-48: 0x____
        If 0x0000 -> valid user address
        If 0xffff -> ERROR! kernel address in user field
    
    Kernel pointer bits 63-48: 0x____
        If 0xffff -> valid kernel address
        If 0x0000 -> ERROR! user address returned by getname()

================================================================================
STEP 10: UNLOAD AND CLEAN
================================================================================

DO:   Unload module.
RUN:  sudo rmmod trace_filename

VERIFY:
    $ sudo dmesg | tail -1
    ARG2: Module unloaded. Missed _____ probes.

DO:   Clean build artifacts (optional).
RUN:  make clean

================================================================================
STEP 11: ERROR PATH EXERCISE
================================================================================

Trigger each error and observe:

TEST 1: Empty path (-ENOENT = -2)
RUN:  cat > test_empty.c << 'EOF'
      #include <fcntl.h>
      int main() { return open("", O_RDWR); }
      EOF
      gcc test_empty.c -o test_empty
      ./test_empty

EXPECTED in dmesg:
    #2. getname. FAIL. err=_____

TEST 2: Path too long (-ENAMETOOLONG = -36)
RUN:  python3 -c "print('a'*4097)" > /tmp/longpath
      # Cannot actually test this easily, but document expected behavior

================================================================================
STEP 12: SUMMARY FILL-IN
================================================================================

COMPLETE THE SUMMARY:

1. open() is transformed by libc to: _____________()
2. The syscall number for openat is: _____
3. getname() is called at line _____ of fs/open.c
4. getname() returns a pointer to: struct _____________
5. The struct is allocated from slab cache: _____________
6. Each allocation is _____ bytes
7. For short paths, name points to: _____________[] at offset _____
8. The user pointer is saved in field: _____________
9. Reference count starts at: _____
10. The function that frees the struct is: _____________()

================================================================================
STEP 13: FAILURE PREDICTIONS
================================================================================

For each failure scenario, write what you EXPECT to happen:

F1: If I forget to load the module before running minimal_open:
    Expected: _________________________________________________

F2: If my filter checks for "wrong_name" instead of "minimal_open":
    Expected: _________________________________________________

F3: If I try to access fn->name without checking IS_ERR(fn) first:
    Expected: _________________________________________________

F4: If getname() receives a NULL pointer from user space:
    Expected error code: _____ (hint: look at ERROR 2)

F5: If the path is exactly 4096 bytes:
    Expected error code: _____ (hint: look at ERROR 5)

================================================================================
ANSWERS (DO NOT LOOK UNTIL YOU COMPLETE THE WORKSHEET)
================================================================================

STEP 02:
    getname() calls: getname_flags()
    With: 3 arguments (filename, 0, NULL)

STEP 03:
    sizeof(struct filename) = 32 bytes

STEP 04:
    names_cache object size: 4096 bytes
    PATH_MAX = 4096

STEP 05:
    First argument register: RDI
    Return value register: RAX
    sizeof(struct filename): 32 bytes
    offsetof(name): 0
    offsetof(uptr): 8

STEP 07:
    sizeof(my_data) = 8 + 16 + 4 = 28 bytes

STEP 12 SUMMARY:
    1. openat()
    2. 257
    3. 1398
    4. filename
    5. names_cache
    6. 4096
    7. iname[], 0x20
    8. uptr
    9. 1
    10. putname()

STEP 13 FAILURE PREDICTIONS:
    F1: No dmesg output (module not probing)
    F2: Only "Module loaded", no trace output (filter skips all)
    F3: Kernel oops/panic (dereferencing error pointer)
    F4: -14 (EFAULT)
    F5: -36 (ENAMETOOLONG)

================================================================================