diff options
author | Matt Mower <mowerm@gmail.com> | 2017-01-25 11:39:38 -0600 |
---|---|---|
committer | Zhao Wei Liew <zhaoweiliew@gmail.com> | 2017-02-11 01:41:20 +0000 |
commit | 55db1141913a77289abd293bca807e0520fd600a (patch) | |
tree | 06eb29d4efd9a8c5c012347f3bad4db4522c5809 | |
parent | 4e0733db7e943a3ee892b7f55db8f91ea3b812db (diff) | |
download | android_bionic-staging/cm-14.1-cafrebase.tar.gz android_bionic-staging/cm-14.1-cafrebase.tar.bz2 android_bionic-staging/cm-14.1-cafrebase.zip |
linker: Allow only specified non-PIE executablesstaging/cm-14.1-cafrebase
For devices that rely on (hopefully a small number of) vendor provided
non position independent executables, a listing of those executables
can be provided to the linker to allow them to run. This limits the
severity of bypassing this security feature entirely.
Header file linker_non_pie_executables.h should be created per-device,
where the syntax of linker_non_pie_executables[] can be referenced
from linker_non_pie.cpp in this commit. The linker is made aware of
the header's existence via:
LINKER_NON_PIE_EXECUTABLES_HEADER_DIR := path/to/include
This commit is designed very closely to commit 'non-pie: Allow only
select libs to be non-pie' (Ife1b2fcc75b418379fc382ae276e63905e8528e0)
by Anthony King, but has been amended for use with Android 7.1.
Change-Id: If4fe98e64bbdd91bfdec5de83247ea3d5688437e
(cherry picked from commit 91b06f97680cfceabba61c1b7859de18d1709312)
-rw-r--r-- | linker/Android.mk | 6 | ||||
-rw-r--r-- | linker/linker.cpp | 64 | ||||
-rw-r--r-- | linker/linker_non_pie.cpp | 36 | ||||
-rw-r--r-- | linker/linker_non_pie.h | 22 |
4 files changed, 94 insertions, 34 deletions
diff --git a/linker/Android.mk b/linker/Android.mk index e729bff54..5e37812b3 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -59,8 +59,10 @@ LOCAL_CPPFLAGS += -DTARGET_NEEDS_PLATFORM_TEXT_RELOCATIONS # We need to access Bionic private headers in the linker. LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/ -ifeq ($(TARGET_NEEDS_NON_PIE_SUPPORT),true) - LOCAL_CFLAGS += -DENABLE_NON_PIE_SUPPORT +ifneq ($(LINKER_NON_PIE_EXECUTABLES_HEADER_DIR),) + LOCAL_CFLAGS += -DENABLE_NON_PIE_SUPPORT + LOCAL_C_INCLUDES += $(LINKER_NON_PIE_EXECUTABLES_HEADER_DIR) + LOCAL_SRC_FILES += linker_non_pie.cpp endif # we don't want crtbegin.o (because we have begin.o), so unset it diff --git a/linker/linker.cpp b/linker/linker.cpp index 583dfd1f6..bff9b9fc6 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -60,6 +60,9 @@ #include "linker_relocs.h" #include "linker_reloc_iterators.h" #include "linker_utils.h" +#ifdef ENABLE_NON_PIE_SUPPORT +#include "linker_non_pie.h" +#endif #include "android-base/strings.h" #include "ziparchive/zip_archive.h" @@ -3132,7 +3135,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset; break; case R_ARM_COPY: -#ifndef ENABLE_NON_PIE_SUPPORT /* * ET_EXEC is not supported so this should not happen. * @@ -3142,52 +3144,43 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r * R_ARM_COPY may only appear in executable objects where e_type is * set to ET_EXEC. */ - DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath()); - return false; -#else - if ((flags_ & FLAG_EXE) == 0) { - /* - * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf - * - * Section 4.6.1.10 "Dynamic relocations" - * R_ARM_COPY may only appear in executable objects where e_type is - * set to ET_EXEC. - * - * TODO: FLAG_EXE is set for both ET_DYN and ET_EXEC executables. - * We should explicitly disallow ET_DYN executables from having - * R_ARM_COPY relocations. - */ +#ifdef ENABLE_NON_PIE_SUPPORT + if (allow_non_pie(get_realpath())) { + if ((flags_ & FLAG_EXE) == 0) { DL_ERR("%s R_ARM_COPY relocations only supported for ET_EXEC", get_realpath()); return false; - } - count_relocation(kRelocCopy); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "RELO %08x <- %d @ %08x %s", reloc, s->st_size, sym_addr, sym_name); - if (reloc == sym_addr) { + } + count_relocation(kRelocCopy); + MARK(rel->r_offset); + TRACE_TYPE(RELO, "RELO %08x <- %d @ %08x %s", reloc, s->st_size, sym_addr, sym_name); + if (reloc == sym_addr) { const ElfW(Sym)* src = nullptr; if (!soinfo_do_lookup(NULL, sym_name, vi, &lsi, global_group, local_group, &src)) { - DL_ERR("%s R_ARM_COPY relocation source cannot be resolved", get_realpath()); - return false; + DL_ERR("%s R_ARM_COPY relocation source cannot be resolved", get_realpath()); + return false; } if (lsi->has_DT_SYMBOLIC) { - DL_ERR("%s invalid R_ARM_COPY relocation against DT_SYMBOLIC shared " - "library %s (built with -Bsymbolic?)", get_realpath(), lsi->soname_); - return false; + DL_ERR("%s invalid R_ARM_COPY relocation against DT_SYMBOLIC shared " + "library %s (built with -Bsymbolic?)", get_realpath(), lsi->soname_); + return false; } if (s->st_size < src->st_size) { - DL_ERR("%s R_ARM_COPY relocation size mismatch (%d < %d)", - get_realpath(), s->st_size, src->st_size); - return false; + DL_ERR("%s R_ARM_COPY relocation size mismatch (%d < %d)", + get_realpath(), s->st_size, src->st_size); + return false; } memcpy(reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(src->st_value + lsi->load_bias), src->st_size); - } else { + } else { DL_ERR("%s R_ARM_COPY relocation target cannot be resolved", get_realpath()); return false; + } + break; } - break; #endif + DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath()); + return false; #elif defined(__i386__) case R_386_32: count_relocation(kRelocRelative); @@ -4393,12 +4386,19 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( } si->dynamic = nullptr; -#ifndef ENABLE_NON_PIE_SUPPORT +#ifdef ENABLE_NON_PIE_SUPPORT + if (allow_non_pie(executable_path)) { + DL_WARN("Non position independent executable (non PIE) allowed: %s", + executable_path); + } else { +#endif ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base); if (elf_hdr->e_type != ET_DYN) { __libc_fatal("\"%s\": error: only position independent executables (PIE) are supported.", args.argv[0]); } +#ifdef ENABLE_NON_PIE_SUPPORT + } #endif // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). diff --git a/linker/linker_non_pie.cpp b/linker/linker_non_pie.cpp new file mode 100644 index 000000000..311f0ac1a --- /dev/null +++ b/linker/linker_non_pie.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * linker_non_pie_executables.h syntax: + * + * const char* linker_non_pie_executables[] = { + * "/path/to/executable1", + * "/path/to/executable2", + * }; + */ + +#include <string.h> +#include "linker_non_pie_executables.h" + +bool allow_non_pie(const char* executable) { + const int array_len = sizeof(linker_non_pie_executables)/sizeof(*linker_non_pie_executables); + for (int i = 0; i < array_len; i++) { + if (!strcmp(linker_non_pie_executables[i], executable)) + return true; + } + return false; +} diff --git a/linker/linker_non_pie.h b/linker/linker_non_pie.h new file mode 100644 index 000000000..f6f66c653 --- /dev/null +++ b/linker/linker_non_pie.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LINKER_NON_PIE_H_ +#define _LINKER_NON_PIE_H_ + +bool allow_non_pie(const char* executable); + +#endif // _LINKER_NON_PIE_H_ |