MTE is actual hardware enforced protection, but simply doesn't have enough bits to reliably detect memory corruption in the general case. It's able to provide a lot of useful deterministic security properties via reserved tags. Normally, the 0 tag is reserved since that's what's used for untagged memory so the random choice never chooses 0. You can also exclude other values, statically or dynamically. This means you can leave things untagged but with PROT_MTE enabled to prevent any tagged pointer accessing them. For example, if you leave register spills, return pointer, etc. untagged then if all stack allocations with potential overflows / use-after-scope are tagged they cannot access that data. As another example, you typically use 0 as the value for currently free allocations which protects them until being allocated again. You can dynamically exclude the adjacent allocations to catch 100% of small/linear overflows along with excluding previous allocation tags. We do this in hardened_malloc with the most recent tags for the 2 adjacent allocations (i.e. current tag if allocated, previous tag if freed already) and the previous tag for the same slot. In the general case, MTE normally provides a 1/15 chance to bypass the protection if you don't statically reserve other tags. Dynamically reserving previous and adjacent random tags doesn't really weaken that.

It's unfortunate that MTE is only 4 bits rather than at least being 8 bits. 1/15 is much worse than 1/255. It could be larger. MTE paves the way for tagging with a larger number of bits, including via a future iteration of MTE with 8 bits or more supported.

It's not specifically a bug finding feature. You can build very useful deterministic exploit protections out of reserved tags, even by simply using the standard 0 reserved tag. 1/15 chance of catching memory corruption in the general case is also nothing to sneeze at especially when combined with other features. If an exploit uses both an arbitrary read vulnerability and then an arbitrary write vulnerability that's 2 opportunities to catch it. It also gets combined with other features which make those exploits less reliable and harder to write. It doesn't exist in isolation. In hardened_malloc, it's just one part of what it does, but it's a huge advancement for it. Tagging the subset of stack allocations with possible overflows or use-after-scope will be another huge step forward.

It would of course be much nicer having massive tags ruling out inter-object memory corruption nearly completely. That doesn't mean MTE is not a good exploit protection and only good for finding bugs. MTE is a lot stronger than most existing exploit mitigations like SSP. SSP provides probabilistic protection against stack buffer overflows by moving the safe variables to the other side and checking a canary on return. If the attacker can leak the canary which is global to the process in userspace, they can write that out as part of it. It also only works against linear or very small (simply by adding padding) overflows. It only has deterministic protection against certain types of C string overflows via a 0 byte if the libc puts one at the start of the canary.