Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++] Upstream ptrauth support in libc++ and libc++abi #84573

Merged
merged 1 commit into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion libcxx/include/typeinfo
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,19 @@ struct __type_info_implementations {
__impl;
};

class _LIBCPP_EXPORTED_FROM_ABI type_info {
# if defined(__arm64__) && __has_cpp_attribute(clang::ptrauth_vtable_pointer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like configuration that might be better suited for a config header?

type_info is weird magic though, so I understand if you disagree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separately, to support ELF platforms that don't define __arm64__ we ended up rewriting the feature check as:

+#if __has_feature(ptrauth_calls) &&                          \
+    (__has_feature(ptrauth_vtable_address_discrimination) || \
+     __has_feature(ptrauth_vtable_type_discrimination)) &&   \
+    __has_cpp_attribute(clang::ptrauth_vtable_pointer)

# if __has_feature(ptrauth_type_info_discriminated_vtable_pointer)
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
[[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, type_discrimination)]]
# else
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
[[clang::ptrauth_vtable_pointer(process_independent, no_address_discrimination, no_extra_discrimination)]]
# endif
# else
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH
# endif

class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH type_info {
type_info& operator=(const type_info&);
type_info(const type_info&);

Expand Down
12 changes: 12 additions & 0 deletions libcxx/src/include/overridable_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
#include <__config>
#include <cstdint>

#if defined(__arm64e__) && __has_feature(ptrauth_calls)
ldionne marked this conversation as resolved.
Show resolved Hide resolved
# include <ptrauth.h>
#endif

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
Expand Down Expand Up @@ -81,6 +85,14 @@ _LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) no
uintptr_t __end = reinterpret_cast<uintptr_t>(&__lcxx_override_end);
uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr);

#if defined(__arm64e__) && __has_feature(ptrauth_calls)
// We must pass a void* to ptrauth_strip since it only accepts a pointer type. Also, in particular,
// we must NOT pass a function pointer, otherwise we will strip the function pointer, and then attempt
// to authenticate and re-sign it when casting it to a uintptr_t again, which will fail because we just
// stripped the function pointer. See rdar://122927845.
__ptr = reinterpret_cast<uintptr_t>(ptrauth_strip(reinterpret_cast<void*>(__ptr), ptrauth_key_function_pointer));
#endif

// Finally, the function was overridden if it falls outside of the section's bounds.
return __ptr < __start || __ptr > __end;
}
Expand Down
19 changes: 19 additions & 0 deletions libcxxabi/src/private_typeinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@
#include <atomic>
#endif

#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
#endif

ldionne marked this conversation as resolved.
Show resolved Hide resolved

template<typename T>
static inline
T *
ldionne marked this conversation as resolved.
Show resolved Hide resolved
get_vtable(T *vtable) {
#if __has_feature(ptrauth_calls)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please give this a more descriptive name than get_vtable, because we already have the vtable in most cases when we call this so it's a touch confusing.

Maybe a name that ties it to ptrauth?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, it may be possible for __builtin_get_vtable() to be used as instead, but I'm not sure what the considerations were when this code was written (or if it predates that builtin?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dynamic_cast machinery had to strip but __builtin_get_vtable always authenticates, so as-is this probably needs to be a manual ptrauth_strip yeah

vtable = ptrauth_strip(vtable, ptrauth_key_cxx_vtable_pointer);
#endif
return vtable;
}

static inline
bool
is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp)
Expand Down Expand Up @@ -103,6 +118,7 @@ void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr
info->dynamic_type = *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));
#else
void **vtable = *static_cast<void ** const *>(static_ptr);
vtable = get_vtable(vtable);
info->offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;
info->dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
Expand Down Expand Up @@ -561,6 +577,7 @@ __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
offset_to_base = __offset_flags >> __offset_shift;
if (is_virtual) {
const char* vtable = *static_cast<const char* const*>(adjustedPtr);
vtable = get_vtable(vtable);
offset_to_base = update_offset_to_base(vtable, offset_to_base);
}
} else if (!is_virtual) {
Expand Down Expand Up @@ -1501,6 +1518,7 @@ __base_class_type_info::search_above_dst(__dynamic_cast_info* info,
if (__offset_flags & __virtual_mask)
{
const char* vtable = *static_cast<const char*const*>(current_ptr);
vtable = get_vtable(vtable);
offset_to_base = update_offset_to_base(vtable, offset_to_base);
}
__base_type->search_above_dst(info, dst_ptr,
Expand All @@ -1521,6 +1539,7 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info,
if (__offset_flags & __virtual_mask)
{
const char* vtable = *static_cast<const char*const*>(current_ptr);
vtable = get_vtable(vtable);
offset_to_base = update_offset_to_base(vtable, offset_to_base);
}
__base_type->search_below_dst(info,
Expand Down
Loading