├── .gitignore ├── README.md ├── TSOEnabler.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── TSOEnabler ├── Info.plist └── TSOEnabler.c ├── enabletso └── enabletso.c └── testtso └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | # CocoaPods 34 | # 35 | # We recommend against adding the Pods directory to your .gitignore. However 36 | # you should judge for yourself, the pros and cons are mentioned at: 37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 38 | # 39 | # Pods/ 40 | # 41 | # Add this line if you want to avoid checking in source code from the Xcode workspace 42 | # *.xcworkspace 43 | 44 | # Carthage 45 | # 46 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 47 | # Carthage/Checkouts 48 | 49 | Carthage/Build/ 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. 54 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 57 | 58 | fastlane/report.xml 59 | fastlane/Preview.html 60 | fastlane/screenshots/**/*.png 61 | fastlane/test_output 62 | 63 | # Code Injection 64 | # 65 | # After new code Injection tools there's a generated folder /iOSInjectionProject 66 | # https://github.com/johnno1962/injectionforxcode 67 | 68 | iOSInjectionProject/ 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TSOEnabler 2 | 3 | A kernel extension that enables total store ordering on Apple silicon, with semantics similar to x86_64's memory model. This is normally done by the kernel through modifications to a special register upon exit from the kernel for programs running under Rosetta 2; however, it is possible to enable this for arbitrary processes (on a per-thread basis, technically) as well by modifying the flag for this feature and letting the kernel enable it for us on. **This extension is designed to work on the M1 (t8101) kernel, where it attempts to automatically detect certain offsets from the kernel image.** If you are looking for the old code for the A12Z (t8020) kernel, it's available [on the t8020 branch](https://github.com/saagarjha/TSOEnabler/tree/t8020). 4 | 5 | ## Installation 6 | 7 | Supposedly, you should be able to use this if you build and sign the kernel extension (disabling SIP if you aren't using a KEXT signing certificate) and drag it into /Library/Extensions. A dialog should come up to prompt you to enable the extension in the Security & Privacy preferences pane, you allow it from there and restart, and it will be installed. (If you're not seeing it, the permissions on the extension might be wrong: try a `chown -R root:wheel`.) In practice this can go wrong in many ways, and I have had luck by "resetting everything" and trying to install after doing the following: 8 | 9 | 1. Reboot into recovery. 10 | 2. Open the Startup Disk application. Your boot security should already be lowered to allow KEXTs from untrusted developers, toggle the checkbox anyways. 11 | 3. Quit Startup Disk and open Terminal. 12 | 4. Remove the kernel extension from the Data volume (likely /Volumes/Data/Library/Extensions/TSOEnabler.kext). 13 | 5. Run `kmutil trigger-panic-medic --volume-root /Volumes/` (again, likely /Volumes/Data). 14 | 15 | (The last two steps work around [bugs in macOS Big Sur beta](https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11-beta-release-notes)). 16 | 17 | After that try installing the kernel extension again. 18 | 19 | ## Usage 20 | 21 | Load the kernel extension with `sudo kextload /Library/Extensions/TSOEnabler.kext`. After that, the `kern.tso_enable` sysctl will be made available to you to read or write. For the reasons described above, you must enable this for all threads of your application if you would like it to work; doing so will also pin these to the high-performance cores of your processor. [A shared library](https://github.com/saagarjha/TSOEnabler/blob/master/enabletso/enabletso.c) that interposes pthreads to automatically enable TSO is also provided for convenience. 22 | -------------------------------------------------------------------------------- /TSOEnabler.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 49311DE726610A0000F825FC /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 49311DE626610A0000F825FC /* main.c */; }; 11 | 49758CCA24D2701800315D38 /* TSOEnabler.c in Sources */ = {isa = PBXBuildFile; fileRef = 49758CC924D2701800315D38 /* TSOEnabler.c */; }; 12 | 499A21982660F97400D85600 /* enabletso.c in Sources */ = {isa = PBXBuildFile; fileRef = 499A21972660F97400D85600 /* enabletso.c */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXCopyFilesBuildPhase section */ 16 | 49311DE226610A0000F825FC /* CopyFiles */ = { 17 | isa = PBXCopyFilesBuildPhase; 18 | buildActionMask = 2147483647; 19 | dstPath = /usr/share/man/man1/; 20 | dstSubfolderSpec = 0; 21 | files = ( 22 | ); 23 | runOnlyForDeploymentPostprocessing = 1; 24 | }; 25 | /* End PBXCopyFilesBuildPhase section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 49311DE426610A0000F825FC /* testtso */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testtso; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 49311DE626610A0000F825FC /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 30 | 49758CC624D2701800315D38 /* TSOEnabler.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TSOEnabler.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 49758CC924D2701800315D38 /* TSOEnabler.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = TSOEnabler.c; sourceTree = ""; }; 32 | 49758CCB24D2701800315D38 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | 499A21922660F95000D85600 /* libenabletso.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libenabletso.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 499A21972660F97400D85600 /* enabletso.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = enabletso.c; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | 49311DE126610A0000F825FC /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | 49758CC324D2701800315D38 /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | 499A21902660F95000D85600 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 49311DE526610A0000F825FC /* testtso */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 49311DE626610A0000F825FC /* main.c */, 66 | ); 67 | path = testtso; 68 | sourceTree = ""; 69 | }; 70 | 49758CBC24D2701800315D38 = { 71 | isa = PBXGroup; 72 | children = ( 73 | 49758CC724D2701800315D38 /* Products */, 74 | 49758CC824D2701800315D38 /* TSOEnabler */, 75 | 499A21962660F95500D85600 /* enabletso */, 76 | 49311DE526610A0000F825FC /* testtso */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 49758CC724D2701800315D38 /* Products */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 49758CC624D2701800315D38 /* TSOEnabler.kext */, 84 | 499A21922660F95000D85600 /* libenabletso.dylib */, 85 | 49311DE426610A0000F825FC /* testtso */, 86 | ); 87 | name = Products; 88 | sourceTree = ""; 89 | }; 90 | 49758CC824D2701800315D38 /* TSOEnabler */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 49758CC924D2701800315D38 /* TSOEnabler.c */, 94 | 49758CCB24D2701800315D38 /* Info.plist */, 95 | ); 96 | path = TSOEnabler; 97 | sourceTree = ""; 98 | }; 99 | 499A21962660F95500D85600 /* enabletso */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 499A21972660F97400D85600 /* enabletso.c */, 103 | ); 104 | path = enabletso; 105 | sourceTree = ""; 106 | }; 107 | /* End PBXGroup section */ 108 | 109 | /* Begin PBXHeadersBuildPhase section */ 110 | 49758CC124D2701800315D38 /* Headers */ = { 111 | isa = PBXHeadersBuildPhase; 112 | buildActionMask = 2147483647; 113 | files = ( 114 | ); 115 | runOnlyForDeploymentPostprocessing = 0; 116 | }; 117 | 499A218E2660F95000D85600 /* Headers */ = { 118 | isa = PBXHeadersBuildPhase; 119 | buildActionMask = 2147483647; 120 | files = ( 121 | ); 122 | runOnlyForDeploymentPostprocessing = 0; 123 | }; 124 | /* End PBXHeadersBuildPhase section */ 125 | 126 | /* Begin PBXNativeTarget section */ 127 | 49311DE326610A0000F825FC /* testtso */ = { 128 | isa = PBXNativeTarget; 129 | buildConfigurationList = 49311DEA26610A0000F825FC /* Build configuration list for PBXNativeTarget "testtso" */; 130 | buildPhases = ( 131 | 49311DE026610A0000F825FC /* Sources */, 132 | 49311DE126610A0000F825FC /* Frameworks */, 133 | 49311DE226610A0000F825FC /* CopyFiles */, 134 | ); 135 | buildRules = ( 136 | ); 137 | dependencies = ( 138 | ); 139 | name = testtso; 140 | productName = testtso; 141 | productReference = 49311DE426610A0000F825FC /* testtso */; 142 | productType = "com.apple.product-type.tool"; 143 | }; 144 | 49758CC524D2701800315D38 /* TSOEnabler */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = 49758CCE24D2701800315D38 /* Build configuration list for PBXNativeTarget "TSOEnabler" */; 147 | buildPhases = ( 148 | 49758CC124D2701800315D38 /* Headers */, 149 | 49758CC224D2701800315D38 /* Sources */, 150 | 49758CC324D2701800315D38 /* Frameworks */, 151 | 49758CC424D2701800315D38 /* Resources */, 152 | ); 153 | buildRules = ( 154 | ); 155 | dependencies = ( 156 | ); 157 | name = TSOEnabler; 158 | productName = TSOEnabler; 159 | productReference = 49758CC624D2701800315D38 /* TSOEnabler.kext */; 160 | productType = "com.apple.product-type.kernel-extension"; 161 | }; 162 | 499A21912660F95000D85600 /* enabletso */ = { 163 | isa = PBXNativeTarget; 164 | buildConfigurationList = 499A21952660F95000D85600 /* Build configuration list for PBXNativeTarget "enabletso" */; 165 | buildPhases = ( 166 | 499A218E2660F95000D85600 /* Headers */, 167 | 499A218F2660F95000D85600 /* Sources */, 168 | 499A21902660F95000D85600 /* Frameworks */, 169 | ); 170 | buildRules = ( 171 | ); 172 | dependencies = ( 173 | ); 174 | name = enabletso; 175 | productName = enabletso; 176 | productReference = 499A21922660F95000D85600 /* libenabletso.dylib */; 177 | productType = "com.apple.product-type.library.dynamic"; 178 | }; 179 | /* End PBXNativeTarget section */ 180 | 181 | /* Begin PBXProject section */ 182 | 49758CBD24D2701800315D38 /* Project object */ = { 183 | isa = PBXProject; 184 | attributes = { 185 | LastUpgradeCheck = 1310; 186 | TargetAttributes = { 187 | 49311DE326610A0000F825FC = { 188 | CreatedOnToolsVersion = 12.5; 189 | }; 190 | 49758CC524D2701800315D38 = { 191 | CreatedOnToolsVersion = 12.0; 192 | }; 193 | 499A21912660F95000D85600 = { 194 | CreatedOnToolsVersion = 12.5; 195 | }; 196 | }; 197 | }; 198 | buildConfigurationList = 49758CC024D2701800315D38 /* Build configuration list for PBXProject "TSOEnabler" */; 199 | compatibilityVersion = "Xcode 9.3"; 200 | developmentRegion = en; 201 | hasScannedForEncodings = 0; 202 | knownRegions = ( 203 | en, 204 | Base, 205 | ); 206 | mainGroup = 49758CBC24D2701800315D38; 207 | productRefGroup = 49758CC724D2701800315D38 /* Products */; 208 | projectDirPath = ""; 209 | projectRoot = ""; 210 | targets = ( 211 | 49758CC524D2701800315D38 /* TSOEnabler */, 212 | 499A21912660F95000D85600 /* enabletso */, 213 | 49311DE326610A0000F825FC /* testtso */, 214 | ); 215 | }; 216 | /* End PBXProject section */ 217 | 218 | /* Begin PBXResourcesBuildPhase section */ 219 | 49758CC424D2701800315D38 /* Resources */ = { 220 | isa = PBXResourcesBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXResourcesBuildPhase section */ 227 | 228 | /* Begin PBXSourcesBuildPhase section */ 229 | 49311DE026610A0000F825FC /* Sources */ = { 230 | isa = PBXSourcesBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | 49311DE726610A0000F825FC /* main.c in Sources */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | 49758CC224D2701800315D38 /* Sources */ = { 238 | isa = PBXSourcesBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | 49758CCA24D2701800315D38 /* TSOEnabler.c in Sources */, 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | }; 245 | 499A218F2660F95000D85600 /* Sources */ = { 246 | isa = PBXSourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | 499A21982660F97400D85600 /* enabletso.c in Sources */, 250 | ); 251 | runOnlyForDeploymentPostprocessing = 0; 252 | }; 253 | /* End PBXSourcesBuildPhase section */ 254 | 255 | /* Begin XCBuildConfiguration section */ 256 | 49311DE826610A0000F825FC /* Debug */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | CODE_SIGN_IDENTITY = "-"; 260 | CODE_SIGN_STYLE = Automatic; 261 | DEVELOPMENT_TEAM = X4A9GH5NN2; 262 | ENABLE_HARDENED_RUNTIME = YES; 263 | MACOSX_DEPLOYMENT_TARGET = 11.3; 264 | PRODUCT_NAME = "$(TARGET_NAME)"; 265 | }; 266 | name = Debug; 267 | }; 268 | 49311DE926610A0000F825FC /* Release */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | CODE_SIGN_IDENTITY = "-"; 272 | CODE_SIGN_STYLE = Automatic; 273 | DEVELOPMENT_TEAM = X4A9GH5NN2; 274 | ENABLE_HARDENED_RUNTIME = YES; 275 | MACOSX_DEPLOYMENT_TARGET = 11.3; 276 | PRODUCT_NAME = "$(TARGET_NAME)"; 277 | }; 278 | name = Release; 279 | }; 280 | 49758CCC24D2701800315D38 /* Debug */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | ALWAYS_SEARCH_USER_PATHS = NO; 284 | CLANG_ANALYZER_NONNULL = YES; 285 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 286 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 287 | CLANG_CXX_LIBRARY = "libc++"; 288 | CLANG_ENABLE_MODULES = YES; 289 | CLANG_ENABLE_OBJC_ARC = YES; 290 | CLANG_ENABLE_OBJC_WEAK = YES; 291 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 292 | CLANG_WARN_BOOL_CONVERSION = YES; 293 | CLANG_WARN_COMMA = YES; 294 | CLANG_WARN_CONSTANT_CONVERSION = YES; 295 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 296 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 297 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 298 | CLANG_WARN_EMPTY_BODY = YES; 299 | CLANG_WARN_ENUM_CONVERSION = YES; 300 | CLANG_WARN_INFINITE_RECURSION = YES; 301 | CLANG_WARN_INT_CONVERSION = YES; 302 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 303 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 304 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 305 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 306 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 307 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 308 | CLANG_WARN_STRICT_PROTOTYPES = YES; 309 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 310 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 311 | CLANG_WARN_UNREACHABLE_CODE = YES; 312 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 313 | COPY_PHASE_STRIP = NO; 314 | DEBUG_INFORMATION_FORMAT = dwarf; 315 | ENABLE_STRICT_OBJC_MSGSEND = YES; 316 | ENABLE_TESTABILITY = YES; 317 | GCC_C_LANGUAGE_STANDARD = gnu11; 318 | GCC_DYNAMIC_NO_PIC = NO; 319 | GCC_NO_COMMON_BLOCKS = YES; 320 | GCC_OPTIMIZATION_LEVEL = 0; 321 | GCC_PREPROCESSOR_DEFINITIONS = ( 322 | "DEBUG=1", 323 | "$(inherited)", 324 | ); 325 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 326 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 327 | GCC_WARN_UNDECLARED_SELECTOR = YES; 328 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 329 | GCC_WARN_UNUSED_FUNCTION = YES; 330 | GCC_WARN_UNUSED_VARIABLE = YES; 331 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 332 | MTL_FAST_MATH = YES; 333 | ONLY_ACTIVE_ARCH = YES; 334 | SDKROOT = macosx; 335 | }; 336 | name = Debug; 337 | }; 338 | 49758CCD24D2701800315D38 /* Release */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | ALWAYS_SEARCH_USER_PATHS = NO; 342 | CLANG_ANALYZER_NONNULL = YES; 343 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 344 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 345 | CLANG_CXX_LIBRARY = "libc++"; 346 | CLANG_ENABLE_MODULES = YES; 347 | CLANG_ENABLE_OBJC_ARC = YES; 348 | CLANG_ENABLE_OBJC_WEAK = YES; 349 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 350 | CLANG_WARN_BOOL_CONVERSION = YES; 351 | CLANG_WARN_COMMA = YES; 352 | CLANG_WARN_CONSTANT_CONVERSION = YES; 353 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 354 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 355 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 356 | CLANG_WARN_EMPTY_BODY = YES; 357 | CLANG_WARN_ENUM_CONVERSION = YES; 358 | CLANG_WARN_INFINITE_RECURSION = YES; 359 | CLANG_WARN_INT_CONVERSION = YES; 360 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 361 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 362 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 363 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 364 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 365 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 366 | CLANG_WARN_STRICT_PROTOTYPES = YES; 367 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 368 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 369 | CLANG_WARN_UNREACHABLE_CODE = YES; 370 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 371 | COPY_PHASE_STRIP = NO; 372 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 373 | ENABLE_NS_ASSERTIONS = NO; 374 | ENABLE_STRICT_OBJC_MSGSEND = YES; 375 | GCC_C_LANGUAGE_STANDARD = gnu11; 376 | GCC_NO_COMMON_BLOCKS = YES; 377 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 378 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 379 | GCC_WARN_UNDECLARED_SELECTOR = YES; 380 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 381 | GCC_WARN_UNUSED_FUNCTION = YES; 382 | GCC_WARN_UNUSED_VARIABLE = YES; 383 | MTL_ENABLE_DEBUG_INFO = NO; 384 | MTL_FAST_MATH = YES; 385 | SDKROOT = macosx; 386 | }; 387 | name = Release; 388 | }; 389 | 49758CCF24D2701800315D38 /* Debug */ = { 390 | isa = XCBuildConfiguration; 391 | buildSettings = { 392 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; 393 | CODE_SIGN_IDENTITY = "Apple Development"; 394 | CODE_SIGN_STYLE = Automatic; 395 | DEVELOPMENT_TEAM = X4A9GH5NN2; 396 | ENABLE_HARDENED_RUNTIME = YES; 397 | INFOPLIST_FILE = TSOEnabler/Info.plist; 398 | MODULE_NAME = com.saagarjha.TSOEnabler; 399 | MODULE_START = TSOEnabler_start; 400 | MODULE_STOP = TSOEnabler_stop; 401 | MODULE_VERSION = 1.0.0d1; 402 | PRODUCT_BUNDLE_IDENTIFIER = com.saagarjha.TSOEnabler; 403 | PRODUCT_NAME = "$(TARGET_NAME)"; 404 | PROVISIONING_PROFILE_SPECIFIER = ""; 405 | RUN_CLANG_STATIC_ANALYZER = YES; 406 | WRAPPER_EXTENSION = kext; 407 | }; 408 | name = Debug; 409 | }; 410 | 49758CD024D2701800315D38 /* Release */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; 414 | CODE_SIGN_IDENTITY = "Apple Development"; 415 | CODE_SIGN_STYLE = Automatic; 416 | DEVELOPMENT_TEAM = X4A9GH5NN2; 417 | ENABLE_HARDENED_RUNTIME = YES; 418 | INFOPLIST_FILE = TSOEnabler/Info.plist; 419 | MODULE_NAME = com.saagarjha.TSOEnabler; 420 | MODULE_START = TSOEnabler_start; 421 | MODULE_STOP = TSOEnabler_stop; 422 | MODULE_VERSION = 1.0.0d1; 423 | PRODUCT_BUNDLE_IDENTIFIER = com.saagarjha.TSOEnabler; 424 | PRODUCT_NAME = "$(TARGET_NAME)"; 425 | PROVISIONING_PROFILE_SPECIFIER = ""; 426 | RUN_CLANG_STATIC_ANALYZER = YES; 427 | WRAPPER_EXTENSION = kext; 428 | }; 429 | name = Release; 430 | }; 431 | 499A21932660F95000D85600 /* Debug */ = { 432 | isa = XCBuildConfiguration; 433 | buildSettings = { 434 | CODE_SIGN_STYLE = Automatic; 435 | DEVELOPMENT_TEAM = X4A9GH5NN2; 436 | DYLIB_COMPATIBILITY_VERSION = 1; 437 | DYLIB_CURRENT_VERSION = 1; 438 | EXECUTABLE_PREFIX = lib; 439 | MACOSX_DEPLOYMENT_TARGET = 11.3; 440 | PRODUCT_NAME = "$(TARGET_NAME)"; 441 | SKIP_INSTALL = YES; 442 | }; 443 | name = Debug; 444 | }; 445 | 499A21942660F95000D85600 /* Release */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | CODE_SIGN_STYLE = Automatic; 449 | DEVELOPMENT_TEAM = X4A9GH5NN2; 450 | DYLIB_COMPATIBILITY_VERSION = 1; 451 | DYLIB_CURRENT_VERSION = 1; 452 | EXECUTABLE_PREFIX = lib; 453 | MACOSX_DEPLOYMENT_TARGET = 11.3; 454 | PRODUCT_NAME = "$(TARGET_NAME)"; 455 | SKIP_INSTALL = YES; 456 | }; 457 | name = Release; 458 | }; 459 | /* End XCBuildConfiguration section */ 460 | 461 | /* Begin XCConfigurationList section */ 462 | 49311DEA26610A0000F825FC /* Build configuration list for PBXNativeTarget "testtso" */ = { 463 | isa = XCConfigurationList; 464 | buildConfigurations = ( 465 | 49311DE826610A0000F825FC /* Debug */, 466 | 49311DE926610A0000F825FC /* Release */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | defaultConfigurationName = Release; 470 | }; 471 | 49758CC024D2701800315D38 /* Build configuration list for PBXProject "TSOEnabler" */ = { 472 | isa = XCConfigurationList; 473 | buildConfigurations = ( 474 | 49758CCC24D2701800315D38 /* Debug */, 475 | 49758CCD24D2701800315D38 /* Release */, 476 | ); 477 | defaultConfigurationIsVisible = 0; 478 | defaultConfigurationName = Release; 479 | }; 480 | 49758CCE24D2701800315D38 /* Build configuration list for PBXNativeTarget "TSOEnabler" */ = { 481 | isa = XCConfigurationList; 482 | buildConfigurations = ( 483 | 49758CCF24D2701800315D38 /* Debug */, 484 | 49758CD024D2701800315D38 /* Release */, 485 | ); 486 | defaultConfigurationIsVisible = 0; 487 | defaultConfigurationName = Release; 488 | }; 489 | 499A21952660F95000D85600 /* Build configuration list for PBXNativeTarget "enabletso" */ = { 490 | isa = XCConfigurationList; 491 | buildConfigurations = ( 492 | 499A21932660F95000D85600 /* Debug */, 493 | 499A21942660F95000D85600 /* Release */, 494 | ); 495 | defaultConfigurationIsVisible = 0; 496 | defaultConfigurationName = Release; 497 | }; 498 | /* End XCConfigurationList section */ 499 | }; 500 | rootObject = 49758CBD24D2701800315D38 /* Project object */; 501 | } 502 | -------------------------------------------------------------------------------- /TSOEnabler.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TSOEnabler.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TSOEnabler/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | OSBundleLibraries 22 | 23 | com.apple.kpi.bsd 24 | 20.0.0 25 | com.apple.kpi.mach 26 | 20.0.0 27 | com.apple.kpi.libkern 28 | 20.0.0 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /TSOEnabler/TSOEnabler.c: -------------------------------------------------------------------------------- 1 | // 2 | // TSOEnabler.c 3 | // TSOEnabler 4 | // 5 | // Created by Saagar Jha on 7/29/20. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define KPTR_FMT "0x%08lx%08lx" 19 | #define KPTR_ARG(x) (unsigned long)(uint32_t)((uintptr_t)(x) >> 32), (unsigned long)(uint32_t)(uintptr_t)(x) 20 | 21 | static int tso_offset = -1; 22 | 23 | static int find_tso_offset_in_text_exec(char *text_exec, uint64_t text_exec_size) { 24 | // Look for this sequence: 25 | // ldr xR, [xR, #OFFSET] 26 | // cbz xR, location 27 | // mrs xR, actlr_el1 28 | // orr xR, xR, #0x2 29 | // orr xR, xR, #0x70 30 | 31 | uint32_t *instructions = (uint32_t *)text_exec; 32 | 33 | for (uint64_t i = 0; i < text_exec_size / sizeof(uint32_t) - 5; ++i) { 34 | if ((instructions[i + 0] & 0xffc00000) == 0xf9400000 && 35 | (instructions[i + 1] & 0x2f000000) == 0x24000000 && 36 | (instructions[i + 2] & 0xffffffe0) == 0xd5381020 && 37 | (instructions[i + 3] & 0xfffffc00) == 0xb27f0000 && 38 | (instructions[i + 4] & 0xfffffc00) == 0xb27c0800) { 39 | printf("TSOEnabler: Found thread pointer read at " KPTR_FMT "\n", KPTR_ARG(instructions + i)); 40 | // Extract the immediate from the ldr. 41 | int tso_offset = (instructions[i] >> 10 & 0xfff) << 3; 42 | printf("TSOEnabler: TSO offset is %d\n", tso_offset); 43 | return tso_offset; 44 | } 45 | } 46 | return -1; 47 | } 48 | 49 | static int find_tso_offset(void) { 50 | // Find the kernel base. First, get the address of something in __TEXT_EXEC 51 | // (thank you Siguza for the idea to use vbar_el1!): 52 | uintptr_t exception_vector; 53 | __asm__("mrs %0, vbar_el1" 54 | : "=r"(exception_vector)); 55 | 56 | printf("TSOEnabler: Exception vector is at " KPTR_FMT "\n", KPTR_ARG(exception_vector)); 57 | 58 | // Then, iterate backwards to find the kernel (not fileset) Mach-O header. 59 | uintptr_t address = exception_vector & ~(PAGE_SIZE - 1); 60 | 61 | uint32_t magic; 62 | do { 63 | do { 64 | address -= PAGE_SIZE; 65 | } while ((void)memcpy(&magic, (void *)address, sizeof(magic)), magic != MH_MAGIC_64); 66 | } while (((struct mach_header_64 *)address)->filetype != MH_EXECUTE); 67 | 68 | printf("TSOEnabler: Found kernel __TEXT base at " KPTR_FMT "\n", KPTR_ARG(address)); 69 | 70 | ptrdiff_t slide = -1; 71 | uintptr_t text_exec_base = 0; 72 | uint64_t text_exec_size = 0; 73 | struct mach_header_64 *header = (struct mach_header_64 *)address; 74 | address += sizeof(*header); 75 | for (int i = 0; i < header->ncmds; ++i) { 76 | struct load_command *command = (struct load_command *)address; 77 | if (command->cmd == LC_SEGMENT_64) { 78 | struct segment_command_64 *segment = (struct segment_command_64 *)command; 79 | if (!strcmp(segment->segname, "__TEXT")) { 80 | // Will probably be 0, because iBoot slides these. 81 | slide = (uintptr_t)header - segment->vmaddr; 82 | } else if (!strcmp(segment->segname, "__TEXT_EXEC")) { 83 | text_exec_base = segment->vmaddr; 84 | text_exec_size = segment->vmsize; 85 | } 86 | } 87 | address += command->cmdsize; 88 | } 89 | 90 | if (slide < 0 || !text_exec_base) { 91 | return -1; 92 | } 93 | 94 | char *text_exec = (char *)(text_exec_base + slide); 95 | 96 | printf("TSOEnabler: Kernel slide is 0x%llx, and __TEXT_EXEC is at " KPTR_FMT " with size 0x%llx\n", (long long)slide, KPTR_ARG(text_exec), text_exec_size); 97 | 98 | return find_tso_offset_in_text_exec(text_exec, text_exec_size); 99 | } 100 | 101 | static int sysctl_tso_enable SYSCTL_HANDLER_ARGS { 102 | printf("TSOEnabler: got request from %d\n", proc_selfpid()); 103 | 104 | char *thread_pointer; 105 | __asm__("mrs %0, tpidr_el1" 106 | : "=r"(thread_pointer)); 107 | 108 | int in; 109 | int error = SYSCTL_IN(req, &in, sizeof(in)); 110 | 111 | // Write to TSO 112 | if (!error && req->newptr) { 113 | printf("TSOEnabler: setting TSO to %d\n", in); 114 | (thread_pointer[tso_offset] = in); 115 | // Read TSO 116 | } else if (!error) { 117 | int out = thread_pointer[tso_offset]; 118 | printf("TSOEnabler: TSO is %d\n", out); 119 | error = SYSCTL_OUT(req, &out, sizeof(out)); 120 | } 121 | 122 | if (error) { 123 | printf("TSOEnabler: request failed with error %d\n", error); 124 | } 125 | 126 | return error; 127 | } 128 | 129 | SYSCTL_PROC(_kern, OID_AUTO, tso_enable, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, NULL, 0, &sysctl_tso_enable, "I", "Enable TSO"); 130 | 131 | kern_return_t TSOEnabler_start(kmod_info_t *ki, void *d) { 132 | printf("TSOEnabler: TSOEnabler_start()\n"); 133 | tso_offset = find_tso_offset(); 134 | if (tso_offset >= 0) { 135 | sysctl_register_oid(&sysctl__kern_tso_enable); 136 | } else { 137 | printf("TSOEnabler: couldn't find TSO offset!\n"); 138 | } 139 | return KERN_SUCCESS; 140 | } 141 | 142 | kern_return_t TSOEnabler_stop(kmod_info_t *ki, void *d) { 143 | if (tso_offset >= 0) { 144 | sysctl_unregister_oid(&sysctl__kern_tso_enable); 145 | } 146 | printf("TSOEnabler: TSOEnabler_stop()\n"); 147 | return KERN_SUCCESS; 148 | } 149 | -------------------------------------------------------------------------------- /enabletso/enabletso.c: -------------------------------------------------------------------------------- 1 | // 2 | // enabletso.c 3 | // enabletso 4 | // 5 | // Created by Saagar Jha on 5/28/21. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | __attribute__((constructor)) static void set_tso() { 15 | int new = 1; 16 | sysctlbyname("kern.tso_enable", NULL, NULL, &new, sizeof(new)); 17 | } 18 | 19 | typedef struct { 20 | void *(*function)(void *); 21 | void *argument; 22 | } pthread_context; 23 | 24 | static pthread_context context_arena[4096 /* ought to be enough for anybody */]; 25 | static atomic_size_t arena_top = sizeof(context_arena) / sizeof(*context_arena); 26 | 27 | static void *set_tso_trampoline(void *argument) { 28 | set_tso(); 29 | pthread_context *context = (pthread_context *)argument; 30 | return context->function(context->argument); 31 | } 32 | 33 | int overriden_pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { 34 | size_t context; 35 | if ((context = --arena_top)) { 36 | context_arena[context] = (pthread_context){start_routine, arg}; 37 | return pthread_create(thread, attr, set_tso_trampoline, context_arena + context); 38 | } else { 39 | return EAGAIN; 40 | } 41 | } 42 | 43 | __attribute__((used, section("__DATA,__interpose"))) static struct { 44 | int (*overriden_pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); 45 | int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); 46 | } pthread_create_interpose = {overriden_pthread_create, pthread_create}; 47 | -------------------------------------------------------------------------------- /testtso/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // testtso 4 | // 5 | // Created by Saagar Jha on 5/28/21. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | atomic_uint barrier; 15 | atomic_uint data[10000]; 16 | 17 | void *writer(void *unused) { 18 | (void)unused; 19 | while (true) { 20 | for (size_t i = 0; i < sizeof(data) / sizeof(*data); ++i) { 21 | atomic_fetch_add_explicit(data + i, 1, memory_order_relaxed); 22 | // https://bugs.llvm.org/show_bug.cgi?id=50564 23 | // atomic_signal_fence(memory_order_acq_rel); 24 | } 25 | atomic_fetch_add_explicit(&barrier, 1, memory_order_release); 26 | } 27 | return NULL; 28 | } 29 | 30 | void *reader(void *unused) { 31 | (void)unused; 32 | unsigned int count = 0; 33 | while (true) { 34 | for (size_t i = 0; i < sizeof(data) / sizeof(*data) - 1; ++i) { 35 | unsigned int value2 = atomic_load_explicit(data + i + 1, memory_order_relaxed); 36 | // https://bugs.llvm.org/show_bug.cgi?id=50564 37 | // atomic_signal_fence(memory_order_acq_rel); 38 | unsigned int value1 = atomic_load_explicit(data + i, memory_order_relaxed); 39 | if (value1 < value2) { 40 | exit(0); 41 | } 42 | } 43 | 44 | while (count == atomic_load_explicit(&barrier, memory_order_acquire)) 45 | ; 46 | ++count; 47 | } 48 | return NULL; 49 | } 50 | 51 | int main() { 52 | pthread_t writer_thread; 53 | pthread_t reader_thread; 54 | pthread_create(&writer_thread, NULL, writer, NULL); 55 | pthread_create(&reader_thread, NULL, reader, NULL); 56 | pthread_join(reader_thread, NULL); 57 | pthread_join(writer_thread, NULL); 58 | } 59 | --------------------------------------------------------------------------------