Not really possible, I think. C is a language that's basically built on memory aliasing and pointer arithmetic: every variable is represented as a location in memory, but there is no guarantee that each memory location is only represented once (there can be many variables pointing to the same memory address). The Rust borrow checker needs pretty much the opposite guarantee: every declared variable has full control over its memory location, and if two pieces of code need to share memory there needs to be an explicit protocol for delegating access.
And it's not like pointers are a rare occurrence in C. This mechanism is used pretty much everywhere: accessing array values, parameter pass-by-reference, function output parameters, string manipulation. There's no concept of function purity either, so no way to guarantee in the function definition that a function cannot outstep its bounds. Sure, there are certain safe coding conventions and rules about what you can or cannot do in a C program, but fundamentally proving that a certain memory location is only accessed through a certain variable is only possible by just running the program exhaustively -- or by confining yourself to a subset of C.
But when you only allow a subset of C, it's no longer "C with a borrow checker", especially given the ubiquitous use of pointers for standard language features. It quickly becomes "we hobbled C because we need more guarantees". To take a quote from the D manual [0], to guarantee memory safety you need to disallow:
- Casts that break the type system.
- Modification of pointer values.
- Taking the address of a local variable or function parameter.
[0]
https://dlang.org/spec/memory-safe-d.html