/ secure / chk_fail.c
chk_fail.c
  1  /*
  2   * Copyright (c) 2007-2013 Apple Inc. All rights reserved.
  3   *
  4   * @APPLE_LICENSE_HEADER_START@
  5   *
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   *
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   *
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  
 24  #include <os/assumes.h>
 25  #include <stdint.h>
 26  #include <TargetConditionals.h>
 27  #include "crt_externs.h"
 28  
 29  #ifndef PR_13085474_CHECK
 30  #define PR_13085474_CHECK TARGET_OS_OSX
 31  #endif
 32  
 33  #if PR_13085474_CHECK
 34  /* Some shipped applications fail this check and were tested against
 35   * versions of these functions that supported overlapping buffers.
 36   *
 37   * We would rather let such applications run, using the old memmove
 38   * implementation, than abort() because they can't use the new
 39   * implementation.
 40   */
 41  
 42  #include <libkern/OSAtomic.h>
 43  #include <mach-o/dyld.h>
 44  #include <mach-o/dyld_priv.h>
 45  #if TARGET_OS_OSX
 46  #define START_VERSION dyld_platform_version_macOS_10_9
 47  #else
 48  #error "This platform should not build with PR_13085474_CHECK=1"
 49  #endif
 50  #endif /* !PR_13085474_CHECK */
 51  
 52  /* For PR_13085474_CHECK set, we initialize __chk_assert_no_overlap to
 53   * 1 initially and then reset it to 0 if the main image of the process
 54   * was linked earlier than 10.9.
 55   *
 56   * If PR_13085474_CHECK is zero, then we never do any sdk version checking
 57   * and always do overlap checks.
 58   */
 59  __attribute__ ((visibility ("hidden")))
 60  uint32_t __chk_assert_no_overlap = 1;
 61  
 62  #if PR_13085474_CHECK
 63  static bool
 64  __chk_assert_sdk_pre_start(const struct mach_header *mh) {
 65    return (dyld_get_active_platform() == PLATFORM_MACOS &&
 66        !dyld_sdk_at_least(mh, START_VERSION));
 67  }
 68  #endif
 69  
 70  __attribute__ ((visibility ("hidden")))
 71  void __chk_init(void) {
 72  #if PR_13085474_CHECK
 73    if (__chk_assert_sdk_pre_start((const struct mach_header *)
 74          _NSGetMachExecuteHeader())) {
 75      __chk_assert_no_overlap = 0;
 76    }
 77  #endif
 78  }
 79  
 80  __attribute__ ((visibility ("hidden")))
 81  __attribute__ ((noreturn))
 82  void
 83  __chk_fail_overflow (void) {
 84    os_crash("detected buffer overflow");
 85  }
 86  
 87  __attribute__ ((visibility ("hidden")))
 88  __attribute__ ((noreturn))
 89  void
 90  __chk_fail_overlap (void) {
 91    os_crash("detected source and destination buffer overlap");
 92  }
 93  
 94  __attribute__ ((visibility ("hidden")))
 95  void
 96  __chk_overlap (const void *_a, size_t an, const void *_b, size_t bn) {
 97    uintptr_t a = (uintptr_t)_a;
 98    uintptr_t b = (uintptr_t)_b;
 99  
100    if (__builtin_expect(an == 0 || bn == 0, 0)) {
101      return;
102    } else if (__builtin_expect(a == b, 0)) {
103      __chk_fail_overlap();
104    } else if (a < b) {
105      if (__builtin_expect(a + an > b, 0))
106        __chk_fail_overlap();
107    } else { // b < a
108      if (__builtin_expect(b + bn > a, 0))
109        __chk_fail_overlap();
110    }
111  }