From c6e015e2c8293cd1c926217765eb9f8443541efb Mon Sep 17 00:00:00 2001 From: yezengruan Date: Thu, 24 Nov 2022 14:38:20 +0800 Subject: [PATCH] sync from src-openeuler libcareplus Signed-off-by: yezengruan --- .gitattributes | 1 + .travis.yml | 14 ++ Makefile | 2 +- README.en.md | 8 +- README.md | 8 +- README.rst | 149 +++++++++++++++ dist/selinux/libcare.te | 2 + libcareplus.spec | 33 ++-- patches/glibc/2.17/glibc-rh1183545.patch | 230 +++++++++++++++++++++++ samples/ghost/README.rst | 11 ++ 10 files changed, 438 insertions(+), 20 deletions(-) create mode 100644 .gitattributes create mode 100644 .travis.yml create mode 100644 README.rst create mode 100644 patches/glibc/2.17/glibc-rh1183545.patch diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d72fd52 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pdf binary diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f3ccb4e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +script: make tests + +language: c + +dist: trusty +sudo: required + +addons: + apt: + packages: + - elfutils + - libelf-dev + - libunwind8-dev + - realpath diff --git a/Makefile b/Makefile index 2da227f..c5a2837 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ - +#dummy all: src diff --git a/README.en.md b/README.en.md index 3077b91..48ade2f 100644 --- a/README.en.md +++ b/README.en.md @@ -17,19 +17,19 @@ For more information about the design of LibcarePlus, see the `LibcarePlus Desig #### Installation -Refer to the `LibcarePlus Intallation Guide` to install LibcarePlus. +Refer to the [LibcarePlus Intallation Guide](https://gitee.com/openeuler/docs/blob/master/docs/en/docs/Virtualization/LibcarePlus.md#installing-libcareplus) to install LibcarePlus. #### User Guide Refer to: -* LibcarePlus Patch Make Tutorial -* LibcarePlus Patch Apply Tutorial +* [LibcarePlus Patch Make Tutorial](https://gitee.com/openeuler/docs/blob/master/docs/en/docs/Virtualization/LibcarePlus.md#creating-libcareplus-hot-patches) +* [LibcarePlus Patch Apply Tutorial](https://gitee.com/openeuler/docs/blob/master/docs/en/docs/Virtualization/LibcarePlus.md#applying-the-libcareplus-hot-patch) to help you make the patch and apply it to the target process. #### Contribution Any contributors are welcome to join this project, and we are glad to provide help and guidance needed. -Developers can post an issue on this project and submit a pull request to join the development process. \ No newline at end of file +Developers can post an issue on this project and submit a pull request to join the development process. diff --git a/README.md b/README.md index 78a9541..e7df4cc 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,17 @@ LibcarePlus的发展目标是对x86_64和aarch64等常见体系结构提供用 #### 安装教程 -请参考`LibcarePlus安装指南`来完成LibcarePlus的安装。 +请参考[LibcarePlus安装指南](https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/Virtualization/LibcarePlus.md#安装-libcareplus)来完成LibcarePlus的安装。 #### 使用说明 请参考: -* LibcarePlus热补丁制作指导 -* LibcarePlus热补丁应用指导 +* [LibcarePlus热补丁制作指导](https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/Virtualization/LibcarePlus.md#制作-libcareplus-热补丁) +* [LibcarePlus热补丁应用指导](https://gitee.com/openeuler/docs/blob/master/docs/zh/docs/Virtualization/LibcarePlus.md#应用-libcareplus-热补丁) 来完成补丁的制作和打补丁的操作流程。 #### 参与贡献 -我们非常欢迎新贡献者的加入,并且非常乐意为新的贡献者提供指导和帮助。 开发者可以通过在本仓库提Issue来描述需求,并通过PR体检提交代码的方式参与开发。 \ No newline at end of file +我们非常欢迎新贡献者的加入,并且非常乐意为新的贡献者提供指导和帮助。 开发者可以通过在本仓库提Issue来描述需求,并通过PR体检提交代码的方式参与开发。 diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..932b7c5 --- /dev/null +++ b/README.rst @@ -0,0 +1,149 @@ +LibCare -- Patch Userspace Code on Live Processes +================================================= + +.. image:: https://travis-ci.org/cloudlinux/libcare.svg?branch=master + :target: https://travis-ci.org/cloudlinux/libcare + +Welcome to LibCare --- Live Patch Updates for Userspace Processes and Libraries. + +LibCare delivers live patches to any of your Linux executables or libraries at +the runtime, without the need for restart of your applications. Most +frequently it is used to perform critical security updates such as glibc's +GHOST_ (aka CVE-2015-0235, see how we deal with it in `GHOST sample`_) and +QEMU's `CVE-2017-2615`_, but can also be used for serious bug fixes on the fly +to avoid interruption of service (see `server sample`_). + +See https://kernelcare.com for live Linux Kernel updates also. + +.. _GHOST: https://access.redhat.com/articles/1332213 +.. _`GHOST sample`: samples/ghost/README.rst +.. _`CVE-2017-2615`: https://www.rapid7.com/db/vulnerabilities/centos_linux-cve-2017-2615 +.. _`server sample`: samples/server/README.rst + +FAQ +~~~ + +How the live patches are generated? +----------------------------------- + +We use the same code generating procedure we used in production for years in +kernelcare.com: + +#. both original and patched source code are translated to assembler, +#. corresponding assembler files are compared and new instrumented assembler + code is generated, where patches are stored into special ELF sections, +#. instrumented assembler code is compiled using target project's build system + while patch ELF sections are collected in binaries', +#. binary patch files are extracted from the ELF sections. + +The `libcare-patch-make`_ script is a handy script for the patch generation for a +makeable project. Just do: + +.. code:: shell + + $ src/libcare-patch-make some_serious_bug.patch + +And find binary patches for all the deliverables of the project in the +``patchroot`` directory. See our `simple server `__ +for usage sample. + +For more details follow to the `patch preparation +`__ chapter of the `internals +`__. + +.. _`libcare-patch-make`: docs/libcare-patch-make.rst + +How the live patches are applied? +--------------------------------- + +It is a lot like loading a shared library into another process' memory: + +#. our binary `libcare-ctl`_ (the doctor) attaches to a patient via + `ptrace(2)`_, +#. patient's objects are examined by the doctor, +#. doctor puppets the patient to allocate patch memory near the original + object, +#. references in the patch are resolved by the doctor, the patch + code is ready to be executed now, +#. doctor rewrites targeted original functions with unconditional jumps to the + appropriate patched versions, ensuring that no thread of patient is + executing them first. + +.. _`ptrace(2)`: http://man7.org/linux/man-pages/man2/ptrace.2.html +.. _libcare-ctl: docs/libcare-ctl.rst + +Now the patient executes patched versions of the functions. + +For more details follow to the `Patching `__ +chapter of the `internals `__. + +Will my patches re-apply if I restart the process? +-------------------------------------------------- + +Not at the moment. We only track start of the new processes for the tests, see +`here `__. + +Does live patching affect performance? +-------------------------------------- + +Negligibly. Since code patches simply redirect execution from original code +functions to the new ones the overhead is small and comparable to +additional “jmp” instruction. + +Installation and dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. _`installation`: +.. _`installation guide`: + +All the Linux-distros with available ``libunwind``, ``elfutils`` and ``binutils`` +packages are supported. + +However, the ``libcare`` is only tested on Ubuntu from 12.04 to 16.04 and on +CentOS from 6.8 to 7.x. + +Dependencies +------------ + +To install the dependencies on RHEL/CentOS do the following: + +.. code:: console + + $ sudo yum install -y binutils elfutils elfutils-libelf-devel libunwind-devel + +To install the dependencies on Debian/Ubuntu do the following: + +.. code:: console + + $ sudo apt-get install -y binutils elfutils libelf-dev libunwind-dev + +Building ``libcare`` +-------------------- + +To build ``libcare`` emit at project's root dir: + +.. code:: console + + $ make -C src + ... + +This should build all the utilities required to produce a patch out of some +project's source code. + +It is highly recommended to run the tests as well, enabling Doctor +``libcare-ctl`` to attach ``ptrace``\ cles to any of the processes first: + +.. code:: console + + $ sudo setcap cap_sys_ptrace+ep ./src/libcare-ctl + $ make -C tests && echo OK + ... + OK + +Now all the required tools are built and we can build some patches. Skip to +`server sample`_ for that. + +How does it work? +----------------- + +Internals are quite confusing and are described `here `__. diff --git a/dist/selinux/libcare.te b/dist/selinux/libcare.te index 670c026..9c7a5ef 100644 --- a/dist/selinux/libcare.te +++ b/dist/selinux/libcare.te @@ -49,6 +49,8 @@ allow libcare_t libcare_file_t: file exec_file_perms; allow libcare_t libcare_file_t: dir list_dir_perms; allow libcare_t libcare_file_t: lnk_file read_lnk_file_perms; +allow init_t var_run_t:lnk_file create; + # to read patient's /proc entries and be able to attach to it allow libcare_t self: capability { dac_override dac_read_search sys_ptrace }; diff --git a/libcareplus.spec b/libcareplus.spec index fd446e0..7019265 100644 --- a/libcareplus.spec +++ b/libcareplus.spec @@ -1,24 +1,25 @@ -Version: 0.1.4 +%define with_selinux 1 + +Version: 1.0.1 Name: libcareplus Summary: LibcarePlus tools -Release: 2%{?dist} +Release: 1 Group: Applications/System License: GPLv2 Url: https://gitee.com/openeuler/libcareplus -Source0: %{name}-%{version}.tar.gz -ExclusiveArch: x86_64 -BuildRequires: elfutils-libelf-devel libunwind-devel +Source0: https://gitee.com/openeuler/libcareplus/release/download/v%{version}/%{name}-%{version}.tar.gz + +BuildRequires: elfutils-libelf-devel libunwind-devel gcc systemd %if 0%{with selinux} BuildRequires: checkpolicy BuildRequires: selinux-policy-devel -BuildRequires: /usr/share/selinux/devel/policyhelp %endif BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %if 0%{with selinux} -Requires: libcare-selinux = %{version}-%{release} +Requires: libcareplus-selinux = %{version}-%{release} %endif %description @@ -50,7 +51,9 @@ LibcarePlus devel files. %autopatch -p1 %build - +cd src +sh ./config +cd ../ make -C src %if 0%{with selinux} make -C dist/selinux @@ -71,6 +74,9 @@ make -C dist/selinux install \ install -m 0644 -D dist/libcare.preset %{buildroot}%{_presetdir}/90-libcare.preset +install -m 0500 scripts/pkgbuild %{buildroot}%{_bindir}/libcare-pkgbuild +install -m 0500 scripts/de-offset-syms.awk %{buildroot}%{_bindir}/de-offset-syms.awk +install -m 0644 -D scripts/example_info %{buildroot}/usr/share/libcareplus/qemu_example_info %pre /usr/sbin/groupadd libcare -r 2>/dev/null || : @@ -88,11 +94,16 @@ rm -rf $RPM_BUILD_ROOT %defattr(-,root,root) %{_bindir}/libcare-cc %{_bindir}/libcare-patch-make +%{_bindir}/libcare-dump %{_bindir}/kpatch_gensrc %{_bindir}/kpatch_strip %{_bindir}/kpatch_make %{_bindir}/libcare-server %{_bindir}/libcare-client +%{_bindir}/libcare-pkgbuild +%{_bindir}/de-offset-syms.awk +/usr/share/libcareplus/qemu_example_info + %if 0%{with selinux} %files selinux @@ -134,8 +145,8 @@ exit 0 %endif %changelog -* Mon Apr 26 2021 Chuan Zheng -- gensrc: skip vector instruction in str_do_gotpcrel +* Thu Nov 24 2022 yezengruan 1.0.1-1 +- libcareplus update to version 1.0.1 -* Tue Dec 8 2020 Ying Fang +* Tue Dec 08 2020 Ying Fang - 0.1.4-1 - Init the libcareplus package spec diff --git a/patches/glibc/2.17/glibc-rh1183545.patch b/patches/glibc/2.17/glibc-rh1183545.patch new file mode 100644 index 0000000..6bb1e0b --- /dev/null +++ b/patches/glibc/2.17/glibc-rh1183545.patch @@ -0,0 +1,230 @@ +commit d5dd6189d506068ed11c8bfa1e1e9bffde04decd +Author: Andreas Schwab +Date: Mon Jan 21 17:41:28 2013 +0100 + + Fix parsing of numeric hosts in gethostbyname_r + +diff --git a/nss/digits_dots.c b/nss/digits_dots.c +index 2b86295..e007ef4 100644 +--- a/nss/digits_dots.c ++++ b/nss/digits_dots.c +@@ -46,7 +46,10 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + { + if (h_errnop) + *h_errnop = NETDB_INTERNAL; +- *result = NULL; ++ if (buffer_size == NULL) ++ *status = NSS_STATUS_TRYAGAIN; ++ else ++ *result = NULL; + return -1; + } + +@@ -83,14 +86,16 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + } + + size_needed = (sizeof (*host_addr) +- + sizeof (*h_addr_ptrs) + strlen (name) + 1); ++ + sizeof (*h_addr_ptrs) ++ + sizeof (*h_alias_ptr) + strlen (name) + 1); + + if (buffer_size == NULL) + { + if (buflen < size_needed) + { ++ *status = NSS_STATUS_TRYAGAIN; + if (h_errnop != NULL) +- *h_errnop = TRY_AGAIN; ++ *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + goto done; + } +@@ -109,7 +114,7 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + *buffer_size = 0; + __set_errno (save); + if (h_errnop != NULL) +- *h_errnop = TRY_AGAIN; ++ *h_errnop = NETDB_INTERNAL; + *result = NULL; + goto done; + } +@@ -149,7 +154,9 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + if (! ok) + { + *h_errnop = HOST_NOT_FOUND; +- if (buffer_size) ++ if (buffer_size == NULL) ++ *status = NSS_STATUS_NOTFOUND; ++ else + *result = NULL; + goto done; + } +@@ -190,7 +197,7 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + if (buffer_size == NULL) + *status = NSS_STATUS_SUCCESS; + else +- *result = resbuf; ++ *result = resbuf; + goto done; + } + +@@ -201,15 +208,6 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + + if ((isxdigit (name[0]) && strchr (name, ':') != NULL) || name[0] == ':') + { +- const char *cp; +- char *hostname; +- typedef unsigned char host_addr_t[16]; +- host_addr_t *host_addr; +- typedef char *host_addr_list_t[2]; +- host_addr_list_t *h_addr_ptrs; +- size_t size_needed; +- int addr_size; +- + switch (af) + { + default: +@@ -225,7 +223,10 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + /* This is not possible. We cannot represent an IPv6 address + in an `struct in_addr' variable. */ + *h_errnop = HOST_NOT_FOUND; +- *result = NULL; ++ if (buffer_size == NULL) ++ *status = NSS_STATUS_NOTFOUND; ++ else ++ *result = NULL; + goto done; + + case AF_INET6: +@@ -233,42 +234,6 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + break; + } + +- size_needed = (sizeof (*host_addr) +- + sizeof (*h_addr_ptrs) + strlen (name) + 1); +- +- if (buffer_size == NULL && buflen < size_needed) +- { +- if (h_errnop != NULL) +- *h_errnop = TRY_AGAIN; +- __set_errno (ERANGE); +- goto done; +- } +- else if (buffer_size != NULL && *buffer_size < size_needed) +- { +- char *new_buf; +- *buffer_size = size_needed; +- new_buf = realloc (*buffer, *buffer_size); +- +- if (new_buf == NULL) +- { +- save = errno; +- free (*buffer); +- __set_errno (save); +- *buffer = NULL; +- *buffer_size = 0; +- *result = NULL; +- goto done; +- } +- *buffer = new_buf; +- } +- +- memset (*buffer, '\0', size_needed); +- +- host_addr = (host_addr_t *) *buffer; +- h_addr_ptrs = (host_addr_list_t *) +- ((char *) host_addr + sizeof (*host_addr)); +- hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs); +- + for (cp = name;; ++cp) + { + if (!*cp) +@@ -281,7 +246,9 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + if (inet_pton (AF_INET6, name, host_addr) <= 0) + { + *h_errnop = HOST_NOT_FOUND; +- if (buffer_size) ++ if (buffer_size == NULL) ++ *status = NSS_STATUS_NOTFOUND; ++ else + *result = NULL; + goto done; + } +diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c +index 1067744..44d00f4 100644 +--- a/nss/getXXbyYY_r.c ++++ b/nss/getXXbyYY_r.c +@@ -179,6 +179,9 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, + case -1: + return errno; + case 1: ++#ifdef NEED_H_ERRNO ++ any_service = true; ++#endif + goto done; + } + #endif +@@ -288,7 +291,7 @@ done: + /* This happens when we weren't able to use a service for reasons other + than the module not being found. In such a case, we'd want to tell the + caller that errno has the real reason for failure. */ +- *h_errnop = NETDB_INTERNAL; ++ *h_errnop = NETDB_INTERNAL; + else if (status != NSS_STATUS_SUCCESS && !any_service) + /* We were not able to use any service. */ + *h_errnop = NO_RECOVERY; +diff --git a/nss/test-digits-dots.c b/nss/test-digits-dots.c +new file mode 100644 +index 0000000..1efa344 +--- /dev/null ++++ b/nss/test-digits-dots.c +@@ -0,0 +1,38 @@ ++/* Copyright (C) 2013 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Testcase for BZ #15014 */ ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ char buf[32]; ++ struct hostent *result = NULL; ++ struct hostent ret; ++ int h_err = 0; ++ int err; ++ ++ err = gethostbyname_r ("1.2.3.4", &ret, buf, sizeof (buf), &result, &h_err); ++ return err == ERANGE && h_err == NETDB_INTERNAL ? EXIT_SUCCESS : EXIT_FAILURE; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" +--- ./nss/Makefile.orig 2016-08-08 00:47:48.562921339 +0300 ++++ ./nss/Makefile 2016-08-08 00:48:33.912193342 +0300 +@@ -38,7 +38,7 @@ + makedb-modules = xmalloc hash-string + extra-objs += $(makedb-modules:=.o) + +-tests = test-netdb tst-nss-test1 ++tests = test-netdb tst-nss-test1 test-digits-dots + xtests = bug-erange + + include ../Makeconfig diff --git a/samples/ghost/README.rst b/samples/ghost/README.rst index da97926..e274b54 100644 --- a/samples/ghost/README.rst +++ b/samples/ghost/README.rst @@ -32,6 +32,17 @@ Now, from inside the container let's install vulnerable version of glibc: glibc-headers-2.17-55.el7 glibc-common-2.17-55.el7 ... +Also we have to downgrade elfutils since newer versions of ``eu-unstrip`` +fail to work with glibc utilities: + +.. code:: console + + [root@... /]# yum downgrade -y --enablerepo=C7.0.1406-base \ + elfutils-devel-0.158-3.el7.x86_64 elfutils-0.158-3.el7.x86_64 \ + elfutils-libs-0.158-3.el7.x86_64 elfutils-libelf-0.158-3.el7.x86_64 \ + elfutils-libelf-devel-0.158-3.el7.x86_64 + ... + Build the ``libcare`` tools: .. code:: console -- Gitee