#!/usr/bin/env bpftrace /* * Capture the complete byte stream fed to AES-CMAC during SMB2 response * signature verification, so it can be diffed against the wire. * * cifs_sig_step() -> aes_cmac_update() is out-of-line and exported, so every * chunk hashed by __cifs_calc_signature() shows up here: * n=0 rq_iov[0]: 64-byte sync hdr (Signature already zeroed) + * 16-byte smb2_read_rsp * n=1.. rq_iter: the destination page-cache folio segments * Concatenated, those are byte-for-byte what the wire PDU should be. * * Run as: * BPFTRACE_MAX_STRLEN=8192 BPFTRACE_PERF_RB_PAGES=1024 \ * bpftrace sigcheck.bt > /var/tmp/sig.out * * Then: * smb2sigcheck.py -k --kernel /var/tmp/sig.out --mid * * sync hdr: Command @12, MessageId @24, SessionId @40, Signature @48 * read_rsp: DataLength @68 * * If fentry on the module function fails to load, swap to: * kprobe:smb2_verify_signature { @h[tid] = *(uint64 *)(*(uint64 *)arg0); } * (rq_iov is the first member of struct smb_rqst, iov_base the first of kvec). */ BEGIN { @needkey = 1; } fentry:cifs:smb2_verify_signature { @h[tid] = (uint64)args.rqst->rq_iov[0].iov_base; @n[tid] = 0; } /* Gated on being inside verification so the key can be tied to a SessionId */ fentry:aes_cmac_preparekey /@needkey && @h[tid] != 0/ { printf("SIGNKEY sid=0x%016llx key=%rh\n", *(uint64 *)((uint8 *)@h[tid] + 40), buf(args.in_key, 16)); @needkey = 0; } fentry:aes_cmac_update /@h[tid] != 0/ { $h = (uint8 *)@h[tid]; /* SMB2_READ only, and only reads small enough to dump in full */ if (*(uint16 *)($h + 12) == 8 && *(uint32 *)($h + 68) <= 8192) { printf("C mid=%llu n=%llu len=%llu %rh\n", *(uint64 *)($h + 24), @n[tid], (uint64)args.data_len, buf(args.data, args.data_len)); @n[tid]++; } } fexit:cifs:smb2_verify_signature { $h = (uint8 *)@h[tid]; if (*(uint16 *)($h + 12) == 8) { /* Signature@48 now holds the locally computed value, not the server's */ printf("R mid=%llu sid=0x%016llx dlen=%u iter=%llu rc=%d calc=%rh\n", *(uint64 *)($h + 24), *(uint64 *)($h + 40), *(uint32 *)($h + 68), (uint64)args.rqst->rq_iter.count, retval, buf($h + 48, 16)); } delete(@h[tid]); delete(@n[tid]); }