View in English

  • Apple Developer
    • 今すぐ始める

    「今すぐ始める」を詳しく見る

    • 概要
    • 学ぶ
    • Apple Developer Program

    最新情報

    • 最新ニュース
    • Hello Developer
    • プラットフォーム

    プラットフォームを詳しく見る

    • Appleプラットフォーム
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    特集

    • デザイン
    • 配信
    • ゲーム
    • アクセサリ
    • Web
    • Home
    • CarPlay
    • テクノロジー

    テクノロジーを詳しく見る

    • 概要
    • Xcode
    • Swift
    • SwiftUI

    特集

    • アクセシビリティ
    • AIと機械学習
    • App Intent
    • Apple Intelligence
    • ゲーム
    • セキュリティ
    • Xcode Cloud
    • コミュニティ

    コミュニティを詳しく見る

    • 概要
    • 「Appleに相談」イベント
    • コミュニティイベント
    • デベロッパフォーラム
    • オープンソース

    特集

    • WWDC
    • Swift Student Challenge
    • デベロッパストーリー
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Center
    • ドキュメント

    ドキュメントを詳しく見る

    • ドキュメントライブラリ
    • テクノロジー概要
    • サンプルコード
    • ヒューマンインターフェイスガイドライン
    • ビデオ

    リリースノート

    • 注目のアップデート
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • ダウンロード

    ダウンロードを詳しく見る

    • すべてのダウンロード
    • オペレーティングシステム
    • アプリ
    • デザインリソース

    特集

    • Xcode
    • TestFlight
    • フォント
    • SF Symbols
    • Icon Composer
    • サポート

    サポートを詳しく見る

    • 概要
    • ヘルプガイド
    • デベロッパフォーラム
    • フィードバックアシスタント
    • お問い合わせ

    特集

    • アカウントヘルプ
    • App Reviewガイドライン
    • App Store Connectヘルプ
    • 近日導入予定の要件
    • 契約およびガイドライン
    • システムステータス
  • クイックリンク

    • イベント
    • ニュース
    • Forum
    • サンプルコード
    • ビデオ
 

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • すべてのビデオ
  • 利用方法
  • 概要
  • トランスクリプト
  • アプリの強化:セキュリティを向上させるための必須戦略

    クパティーノのApple Developer Centerで終日開催されたアクティビティを視聴して、アプリのセキュリティ強化とユーザーのデータ保護について確認しましょう。既存アプリのセキュリティ強化を目指すデベロッパも、新しいプロジェクトを開始しようとしている方も、アプリを基礎から強化する方法をAppleのエンジニアから直接学ぶことができます。

    最新のアプリが直面するセキュリティ面の課題を理解するとともに、ユーザーデータを保護するための多彩なツールやテクノロジーについて確認できます。Memory Integrity Enforcement(MIE)、ポインタ認証、メモリ境界保護などの強力な機能を利用して、CおよびC++のコードベースを保護する方法もご紹介します。さらに、特に高度なセキュリティが必要とされるコンポーネントをSwiftで作成する方法も解説します。Swiftの本質的な安全性と高度な抽象化を活用することで、安全かつハイパフォーマンスなコードを記述できます。また新規および既存のプロジェクトについて、全体的な戦略の構築から具体的な実装までカバーする、明確なセキュリティロードマップを策定するためのガイダンスも提供します。

    リソース

      • HDビデオ
      • SDビデオ
  • このビデオを検索

    こんにちは。ここクパチーノの Appleデベロッパセンターへようこそ。 私はカートです。テクノロジーの 伝道師をしています。 ワールドワイド・デベロッパー・ リレーションズ・チームに所属。 本日、同僚たちと共に、様々なテクニックを ご紹介できることを嬉しく思います。 メモリ安全性の脆弱性を低減することで、 アプリのセキュリティを向上させます。 話したいことはたくさんありますが、 まずは会場についてもう少し詳しく お話ししたいと思います。 Appleデベロッパセンター。

    デベロッパセンターはApple Parkの 一部です。 交流スペースもあり、今日の イベントに最適な会場です。 そしてコラボレーション。

    この部屋はビッグサーです。 素敵な空間で、設備も素晴らしい。 この画面、本当に気に入っています。 幅広い活動をサポートするように 設計されており、 このような対面でのプレゼンテーション、 スタジオ録音、 そして、現在も生放送中です。 こんにちは、世界。

    実験室やブリーフィングルームもある。 また、様々な規模のイベントを開催できる 会議室も備えています。

    これは、世界にある4つのデベロッパセンターのうちの 1つです。 Appleは、デザイナーや開発者向けに、 セッション、ラボ、 ワークショップなどを開催しています。 ここにいる方で、以前にデベロッパセンターに 行ったことがある方はいますか? 素晴らしいですね。初めての方も、 以前お越しいただいた方も、 皆様を心から歓迎いたします。

    私たちのチームは開発者の方々と 交流することが大好きです。 私たちの目標は、Appleの プラットフォーム向けに 最高のアプリを開発できるよう お手伝いすることです。 Web 25以来、私たちは 世界中でラボを含む300以上のアクティビティを 開催してきました。 ワークショップやプレゼンテーション。 来週、私の同僚たちは 私と彼女は、New York市で 新しいデザインに関する ワークショップを主導しています。 ワークショップ参加者は、液体ガラスを実際に 体験することができます。 コードやデザインを更新するにつれて。 お近くまたはオンラインで 開催される今後のイベントの詳細については、 デベロッパをチェックしてください。 今日の議題に入る前に、 参加者同士が一日を通して繋がりを保つための ヒントをいくつかご紹介します。 AppleのWi-Fiネットワークを 使用してください。 誰でもアクセス可能で、 パスワードもありません。 途中で充電が必要になった場合は、 各座席に電源が備わっています。 アームレストの前面にあります。

    本日ご視聴いただいている皆様へ、 これらのプレゼンテーションは録画され、 イベント終了後にオンラインで 視聴可能になります。 動画を録画したり、ライブ配信したりする 必要はありません。

    ただし、写真を撮りたい場合は、 もちろんご自由にどうぞ。

    イベント終了後には、リンク付きの フォローアップ情報もお送りします。 プレゼンテーションで言及された 資料はすべて確認しておきましょう。 そうすれば何も見逃すことはありません。

    予備準備が終わったので、 今日のイベントについて、 もっと詳しくお伝えできるのが楽しみです。

    本日のテーマは、メモリセキュリティの 脆弱性とその対処法です。 人々のデバイスは生活に 欠かせないものとなっている。 彼らのデバイスには、膨大な量の個人データや プライベートな情報が保存されている。

    その結果、攻撃者にとって格好の標的となる。 この情報にアクセスするには。

    本日のプレゼンテーションでは、 メモリのバグを見つけて修正することで、 攻撃者からアプリを保護します。 一般的な保護対策を適用したり、 メモリ安全なコードを記述したりすること。

    オンラインの皆さんへ、 Slidoを使ってAppleのエンジニアに 質問を送ることができます。 ご質問にお答えするチームがおり、 皆様をサポートする準備は万端です。 本日のテーマに集中していただくよう お願いいたします。 チームは、例に関する質問に お答えできることを楽しみにしています。 Slido のプレゼンテーションと一般的な アプリのセキュリティ問題では、 他の人が質問した内容を閲覧したり、 お気に入りの質問に 賛成票を投じたりすることができます。 そして、チームの回答を読んでください。 これは素晴らしい情報源であり、 皆さんの質問に基づいて成り立っていますので、 ぜひ質問してください。

    技術プログラムを開始する前に、 ビッグサーのステージに 特別なゲストをお迎えしたいと思います。 Appleのプラットフォームセキュリティ責任者を 歓迎しましょう。 ピエール=オリヴィエ・マルテル。 ピエール。

    カートさん、ありがとう。

    皆さん、おはようございます。 私の名前はピエール・ オリヴィエ・マルテルです。 私はセキュリティエンジニアリング部門の プラットフォームセキュリティ責任者です。 そして建築グループ。 まず最初に、本日お越しいただき、 またオンラインでご参加いただいた 皆様に感謝申し上げます。 こんなにたくさんの方に お会いできて本当に嬉しいです。 今や、私たちのデバイスが人々にとってどれほど 重要なものになっているかは、 誰もが知っています。 それらを使用する人々、 そしてこれらのデバイスとそれらが 保持するデータを保護する人々、 コミュニケーションであれ、親密な瞬間であれ、 健康情報または財務情報、 プライバシーを構築する理由は そして、セキュリティを製品開発の 初期段階から組み込んでいます。 Appleはハードウェアを深く統合することで 最高のセキュリティを実現しています。 ソフトウェアおよびサービス。 過去15年間、当社製品には、 業界をリードする数々のセキュリティ対策が 組み込まれています。 これらはセキュアブートから、 これは最初の命令から ソフトウェアの完全性を保証する タッチID、フェイスIDなどの認証技術、 そして光学IDを最後まで iMessageやiCloudキーチェーンを 支える暗号化プロトコルを終了する。

    私たちの羅針盤は変わっていません。 セキュリティはデフォルトで有効になっており、 使いやすいものであるべきだと私たちは 考えています。 そしてこの研究の結果、 セキュリティ研究者たちは iPhoneは最も安全で セキュリティの高い消費者向け モバイルデバイスであるという意見に賛成する。

    多くの悪行の共通点は、業界の他のプラットフォームを ターゲットにしている ものも含め、彼らがメモリの安全性に 関する脆弱性を悪用するという のがその理由です。 ここAppleでは、 ​​メモリの安全性を向上させるために 懸命に取り組んできました。例えば、 Swiftのようなメモリ安全な 言語で開発することによって そして、全く新しい緩和策を大規模に展開し、 そのうちのいくつかは、今日皆さんが 耳にするでしょう。 ごく最近、メモリ整合性強制機能を 導入しました。 最新のiPhoneとMacモデルで。 さて、Emmiは独自の技術を組み 合わせた画期的な製品です。 Appleシリコンハードウェアの強みと、 当社の高度なオペレーティングシステムの セキュリティ業界初となる、 デバイス全体で常に メモリの安全性保護を維持し、 妥協することなくデバイスの パフォーマンスについて。

    しかし、この章は私たちが 安全なデバイスをユーザーに 出荷して終わるわけではありません。 Appleデバイスのセキュリティも ルート化されているため 周囲の生態系の強さにこそ、その源泉がある。 そのため、安全なエコシステムへの私たちの取り 組みは、3 番目まで及んでいます。 私たちがデベロッパコミュニティであるあなたと 共に 働くパーティソフトウェアエコシステム、 安全なアプリを提供するため。 そのためには、App Storeと プラットフォームのセキュリティ機能が 連携して動作する必要がある。 そして、この提携がなぜそれほど重要なのか、 その理由を説明しましょう。 攻撃者はプラットフォームを区別しない そして、その上で動作しているアプリ。 彼らは最も弱い部分を探し出す。 そこで、プラットフォームのセキュリティ基準を 体系的に引き上げていくと、 私たちはあらゆる場所でその 意識を高める必要がある。 実際、私たちはあらゆる 場所でこの問題に取り組まなければならない。 つまり、これらの技術をできるだけ 広く普及させるために 協力していく必要があるという ことです。可能な限り。ですから、 私たちがこれまで行ってきた取り 組みを皆さんと共有できることを大変嬉しく 思っています。そして、あなたのアプリに 導入できるようにするためです。 当社がすべてのユーザーを保護するために 使用している高度な防御策の多くを、 このシステムにも適用しています。 それでは、本日はお越しいただき、改めて 感謝申し上げます。ようこそ。それでは、 カートにバトンタッチして、始めましょう。

    ありがとう。

    ありがとう、ピエール。オリヴィエ。 本日の残りの日程の概要は以下のとおりです。 私たちの技術プログラムは 実践的なガイドから始まります。 Appleが自社アプリを保護するために 使用しているのと同じメモリ安全戦略に、 いつ、どのように 型付きアロケータのようなクイックウィンから 各防御層を適用するには、 迅速な書き換えのような長期投資へ さらに、セキュリティ機能の 強化も図られています。

    その後、少し休憩してストレッチをします。 そして、カフェイン入りの飲み 物を楽しむかもしれません。 その後は、記憶、整合性、 執行について深く掘り下げます。 そしてポインター認証。 ハードウェアとソフトウェアの セキュリティ機能2つを網羅 メモリ破損攻撃からどのように保護するか、 そして、あなたのコードがそれらの保護機能を 損なわないようにする方法。 昼食のために80分の休憩を取ります。 その後、さらに3つのプレゼンテーションのためにここに 戻ってください。 C言語と C+ + 言語で境界安全性を採用するための 実践的なガイドから始め、 C言語におけるコンパイラ強制境界注釈について 解説 さらに、 C+ + における 標準ライブラリのチェックを強化しました。

    もう一度短い休憩を取ると、 いよいよゴール目前です。 ここでは、Swiftに 組み込まれているメモリ安全性の保証が C言語と比べてどうなのかを学びます。 C+ + では、パフォーマンスが 重要なコードで新しい低オーバーヘッドの スパン型を使用する方法、 そして段階的に、 安全でないコードベースを段階的に移行する 厳密なメモリ安全モードとC言語との相互運用機能を 使用してSwiftに移植します。

    そして、その日の最後のセッションでは、 アドレスサニタイザーの使い方を学ぶ また、XcodeのThread sanitizerを 使用して、 バッファオーバーフローを事前に検出します。 コードベース内のバグや データ競合を解消するために使用してください。 サニタイザーがメモリの完全性維持をどのように 補完するかについても言及する。

    最後に、ここにいる皆さんのために 今日の締めくくりをしたいと思います。 開発者センターのロビーに集まる Appleのエンジニアと 交流できる交流会です。 そして他の開発者仲間たち。

    それでは、技術プログラムを開始するために、 ビッグサーのステージに マークさんをお迎えしたいと思います。 マーク。

    ありがとう。

    おはようございます。 アップルのセキュリティエンジニアリング部門の マーク・ミッチェルです。 そして、同僚のデビンと共に、 建築チームと連携しました。 今日は、どのように保護できるかについての フレームワークについて説明します。 メモリ安全性の脆弱性からアプリを保護します。

    デビンが慎重に重ね合わせ、組み合わせた戦略 そして今日お話しするのは、 iPhoneがその名声を得た理由です。 入手可能な消費者向け デバイスの中で最も安全なデバイスとして。 本日のセッションでは、 これらの機能が何であるかについて 説明します。それらが何のために 使われるのか、そしてAppleがどのようにそれらを 使用しているかの例を挙げて 説明します。アプリ、 OS、 そしてお客様を守るため。

    Xcodeを使えば、 Appleが採用しているのと同じ 技術を利用できるようになります。 アプリのユーザーを保護するため。

    アプリは私たちの生活の多くの側面に 影響を与えている。 これらは誰もが自分の個人情報を安心して 預けられる不可欠なツールです。 位置情報、閲覧履歴、写真、 メッセージ、財務情報、そして同時に、 これらのアプリとユーザーは インターネットに接続されています。 そのため、それらに存在する セキュリティ上の脆弱性によって、 ユーザーは攻撃にさらされる可能性がある。 これらの攻撃のコストは詐欺から始まる 個人情報の窃盗から恐喝まで、 そして稀な状況では、 物理世界における脅威。

    人々は自分のデータがプライベートかつ 安全に保たれることを期待している。 そして、その約束が守られなければ、 それは信頼の裏切りとなる。

    セキュリティは、プライバシーを可能にする 技術的な基盤である。

    まず、メモリの安全性とは 何かについて概説します。 そして、それが引き起こす 可能性のあるさまざまな種類の脆弱性。

    次に、セキュリティに関する概要を説明します。 アプリを保護するために 使用できるエンジニアリング戦略 そして、私たちがそれらをどのように 自社で効果的に活用してきたかを説明します。 そして最後に、デビンがこれらの戦略を 実践する方法をお見せします。 Xcodeで強化された セキュリティ機能を使用する場合。

    では、メモリの安全性とは 具体的に何を意味するのでしょうか? メモリ安全性のバグは、 最も一般的な脆弱性の1つです。 ソフトウェアでは、攻撃者は メモリ破損を利用して変更を加える。 またはプログラムの動作を妨害する。

    Appleでは、セキュリティエンジニアは メモリの安全性を意図された 観点から考えています およびプログラムにおける意図しない動作。

    通常の使用方法では、このプログラムは デベロッパの意図どおりに動作します。 そして、理にかなった行動のみを行う。 つまり、プログラムの流れは、 一種の迷路のようなものだと考えてください。 迷路を抜ける道こそが暗号だ。 デベロッパは、何らかの操作に 使用されることを意図しています。 また、その他の経路は、 使用されていない、または 到達不可能なコードパスを表しています。

    そして到達不可能な道は 使用していないフレームワークでは、 次のようなことを行います。 カメラで撮影するか、 メールを送信してください。 攻撃者はこれらのメモリ安全性の 脆弱性を利用して、 プログラムを騙して予期しない状態にし、 デベロッパが意図した 動作とは全く異なる動作を実行する。

    この例では、メモリの安全性に 関する脆弱性がどこにあっても 意図された道筋は、迷路を解くための全く 新しい方法へと導く。 あるいは、新たな経路を作成したり 辿ったりすることで、 意図しないコードを実行してしまう 可能性がある。 それは、そのコードを呼び出してアプリに カメラを強制的にオンにさせることを意味する 可能性がある。または メールを送信してください。

    メモリの安全性はセキュリティの 基礎であり、それがなければ、 より高度なセキュリティ特性については 保証できません。 例えば、パスワードのハッシュ化方式がどれほど 強力であっても関係ありません。 攻撃者がアクセス権を取得するだけで メモリの安全性に関する脆弱性を悪用して、 システムに侵入する。

    以下に例を示します。 これはシンプルなログイン機能です。 ユーザーからテキストフィールドに パスワードのコピーを取得し、 デバッグビルドかどうかを確認し、 認証をスキップします。 そうすれば、デベロッパは自分のデスクでより 迅速にテストできるかもしれない そして、パスワードのコピーと比較する 関数を呼び出します。 ハードコードされた秘密情報を受け取り、 ログイン結果を返します。 特に観察眼の鋭い方はお気づきかもしれませんが あの巨大な赤いX印。 明らかにメモリの安全性に脆弱性がある。 このコードには、絶対に コピーしてはいけない部分があります。 ここでは、デベロッパはスタック上に 32文字分のスペースを割り当てています。 パスワードのコピーを保持するため、 しかし、コピーAPIは 利用可能な容量を把握していません。 そして、そのテキストフィールドにある 文字数と同じ数の文字をコピーします。 与えられたバッファに書き込むと、 スタックバッファオーバーフローが発生します。

    記憶の裏側では、おおよそ 次のようなことが起こっている。 ローカルパスワードの保存場所は、 使用されるメモリの直前です。 デバッグログインフラグを保持するため。

    パスワードが例えば18文字であれば、 もちろん安全に収まります。

    しかし、攻撃者が32文字以上送信してきた 場合はどうなるでしょうか?

    では、このプログラムは言語で書かれているため それはメモリ的に安全ではありません。 隣接するメモリ領域を上書きし始めます。 そして、これがデバッグログインフラグを 保存するために使用されるメモリです。

    そしてその結果、デベロッパの意図に関係なく またはこの関数に渡され、 プログラムがこのif文に到達したとき、 値が攻撃者によって 上書きまたは変更された場合、 認証をスキップさせて、 とにかくtrueを返すように強制できる。

    しかし実際には、そのコードにはさらに 深刻な問題がある。 デバッグフラグを上書きすると、攻撃者は 認証なしでログインできるようになります。 しかしメモリ上では、デバッグログインフラグの 後に続くアドレスは プログラムが比較を行うために 呼び出す関数ポインタ。

    攻撃者がさらに長いパスワードを提供すると、 デバッグログインフラグを介して ローカルパスワードバッファから オーバーフローする可能性があります そして、その関数ポインタを 好きなものに変更する。 つまり、プログラムが 比較関数を呼び出そうとすると、 実際には比較することになります。 実際には、攻撃者が選択した 任意の関数が呼び出されることになります。 そして今、攻撃者はこのプロセスを 完全に制御できるようになった。 これらの他のコードパスのいずれかに到達し、 ユーザーデータを盗む可能性があります。

    つまり、その例はバッファオーバーフローです。 これは、メモリ安全性の特性の一つに違反する。 しかし実際には、5つの軸が拘束されている。 安全性はすべてのアクセスを保証します メモリへの書き込みは、 メモリ割り当ての範囲内で行われます。 生涯安全性により、メモリは 有効な期間のみ使用されます。 そして、他の用途に再利用されていない。

    型安全性は、プログラマーが誤って アクセスできないことを保証します。 意図されたものとは異なる 種類のメモリを介して記憶される。

    初期化保証とは、メモリが使用される前に 必ず初期化されることを保証するものです。

    そして最後に、スレッドセーフティにより、 異なるスレッドが踏みつけられることが なくなります。 お互いの記憶に寄り添って。

    では、攻撃は 一般的にどのようなものになるのでしょうか。 一般的に、あらゆる アプリを標的とする攻撃者は、 そのアプリからデータに アクセスしたり、侵害したりするだけでなく そしてそのアプリからデータにアクセスします が、それをステップとして使用します。 他のシステムコンポーネントを攻撃する 一連のバグの最初のステップ、 カーネルに権限を昇格させることさえ可能 プラットフォームのセキュリティモデルを 弱体化させるため、 システム全体からファイルに アクセスしようとしているだけでなく、 しかし、位置情報、写真、連絡先、 マイクなどの他の資産も含まれます。

    つまり、アプリはしばしば、 より大規模な攻撃への入り口となるのです。

    同時に、現代のアプリケーションは 非常に多くの機能があり、 その多くがアクセス権を与えられています これらの資産のほとんどは 通常の使用状況において。 OSがセキュリティ体制を進化させ 続けるにつれて、将来、 攻撃者は、あなたのアプリを悪用するだけで 満足するかもしれません。そして、その環境から アクセスできるデータを収集し、そして、 プラットフォームの残りの部分に 進む必要もありません。 だからこそ、今私たちは 皆セキュリティ対策と並行して、 共に前進していく。

    それでは、Appleで 採用されている戦略について説明しましょう。 メッセージなどのアプリケーションや サービスを保護するため、 Safariとメールのメモリセキュリティに 関する脆弱性。

    十分に複雑なコードベースであれば、どれでも。 脆弱性は常に存在するものだと認識されている。 行き過ぎだ。

    そのため、 Appleでは、 複数のセキュリティエンジニアリング層に 依存しています。 そして互いに補完し合う。

    さらに深く掘り 下げていくことになるでしょう今日 ご紹介する多くのテクノロジーに、 しかし、私はここでその概念を紹介し、 Appleがそれらをどのように適用しようと 考えている かを説明します。そして、それらの有効性を 評価するいくつかの方法そして、 それらをアプリケーションで 使用するために必要な労力。 これから5つの戦略についてお話しします。

    メモリ安全性の脆弱性を不可能にする 方法について解説します。 Swiftのようなメモリ安全な 言語を使用してコード内で メモリを安全に管理します。

    利用可能なリソースを減らすことで 脆弱性をアクセス不能にする方法 攻撃対象領域、

    脆弱性を悪用されないようにする 万が一脆弱性が悪用された場合に備え、 その被害を軽減する対策を講じる。

    そして最後に、見つけるためのいくつかの テクニック そして、コードから脆弱性を排除すること。

    最も包括的なアプローチメモリ安全性の 脆弱性から 防御することは作成がほぼ 不可能な言語を 使用するそもそも。

    Appleは、安全かつ高性能な言語として Swiftに多額の投資を行ってきた。 さらに、購入後すぐに メモリの安全性を確保できます。 それはあなたの多くのアプリケーションを 動かすだけでなく、しかし、 それは私たちのオペレーティングシステムの 一部にも当てはまります。 そしてそれは、セキュリティにとって 重要なコードベースをますます多く含みます。 WebKit、複雑な解析など、 さらに、Secure Enclaveのような 組み込み環境でもファームウェアが処理されます。 もちろん、多くのアプリには既に 大規模なコードベースが構築されています。 C言語ファミリーに属する言語。 それらはメモリ安全性が低い。

    セキュリティ強化により、Fバンドの 安全性などのツールが提供されます。 C言語の注釈も含む およびC++標準ライブラリの強化 バンドの安全に関する ミスを減らすのに役立ちます。 しかし、これらは記憶の安全性を確保するための 足がかりだと考えてください。 それらは最終目標ではない。なぜなら、 他の4つの軸に対応していないからだ。

    C言語ベースの言語とSwiftを 5つの軸で比較すると、 C言語ベースの言語はこれらの 保護機能を一切提供しない。 一方、Swiftは境界チェック配列を使用することで 境界安全性を実現している。 その他、Swift標準ライブラリの 抽象化機能。 自動参照カウントと所有権管理により、 生涯にわたる安全性を確保します。 これは、キャストが実行時に チェックされることを要求することで、 型安全性を保証する。

    Swiftは変数の初期化を要求することで 初期化を保証します。 使用される前に。 また、高速な並行処理により、データ競合を 防ぎ、スレッドセーフティを実現します。

    というわけで、これがその 方法の簡単なツアーです メモリ安全性の脆弱性を不可能にする。 後ほど「Swiftで セキュリティに配慮した コードを書く」セッションをご覧ください。 詳細については、こちらをご覧ください。

    Appleが多用する2つ目の戦略は セキュリティ上重要なコードベースにおいては、 これは攻撃対象領域の縮小として 知られています。 そしてここでの理論は、 開発者やセキュリティエンジニアとして、 コード内のすべての脆弱性を 把握することはできません そして、あなたが頼りにしている フレームワークはそうかもしれません。 しかし、攻撃者がアクセスできる 可能性のあるコードの量を制限することは 可能です。機能に必要な最小限の セットに、これにより、 脆弱性が存在する可能性が大幅に減少します。 アプリ内で実際に使用されるコードの中に。

    Appleはこの技術をシステム全体で 使用しています 攻撃者が作業できるスペースを減らすため、 そしてそれは、制限する技術から 複雑なドキュメント形式を解析して 条件付き機能にすることができます 相手方が信頼できるかどうか ロックダウンモードで全ての機能を無効にする。

    フォーマット制限の例として、 アプリが常にJPEG画像のみを送受信することが わかっている場合、 受信側コードを許可する 他の形式の画像を処理するには、 数百万行の解析コードが必要になります。 攻撃者が脆弱性を探す必要がないようにする。 その場合、即座に影響を与える最善の方法は セキュリティを向上させるには、 JPEG形式が適切かどうかを チェックすることである。 または、コアグラフィックスを設定して、 そのフォーマットのみをプロセスで 解析するようにする 期待どおりのトラフィックが得られない場合は、 トラフィックを停止すればよい。

    アプリが意図せず公開してしまう 可能性のあるもう1つの場所 厳密には必要ではない攻撃対象領域は 直接使用するウェブビューを介して ウェブコンテンツをレンダリングする場合 アプリ内ブラウジングなど また、サードパーティからインポートする 可能性のあるフレームワークを通じて、 広告用SDKのようなもの。

    iOS 26.4以降、 WebKitには Enhanced Security Webviewsと 呼ばれる強力な新しいオプションが2つあります。 これらのモードではアプリを制御できます。 アプリがウェブからのコンテンツを 処理する方法を制御する、 さらにセキュリティ強化策もいくつか講じた。

    デフォルトでは、Wkwebview はすべての パワー、機能、 アプリ内でのWebKitのパフォーマンス、 Safariのセキュリティ対策と アーキテクチャをすべて維持しつつ、 最初の新しいモード制限モード、 互換性を最大限に高めることで、 完全なウェブ互換性を維持します WebKitが現在サポートしているもの、 複雑なフレームワークコードの 大部分を削除しながら さらに、最新のハードウェアセキュリティ対策の 利用を拡大する。

    これらの新しいモードの2番目である 制限モードロックダウンは、さらに進んで、 また、アプリのウェブビューを 選択できる機能も提供します。 ロックダウンモードと同じ極度の保護レベルに、 そして、あまり使われていない ウェブ技術も削除します。 さらに、攻撃者の選択肢を減少させる。

    Appleでは、これらの強化されたセキュリティWebビューの 採用を開始しました。 OS全体、メール機能も含めて。 簡単に見ていきましょう。iOS iOSにおけるキャプティブポータルショートカットと Apple広告について。 まさに今が、それらを試してみる 絶好の機会です。

    攻撃対象領域の縮小は、セキュリティ投資に 対して大きなリターンをもたらします。 しかし、メモリ安全性の脆弱性は 依然として存在するという 前提は依然として必要である。 安全でない言語で書かれた 残りのコードすべてにおいて。

    そのような場合、次に最も効果的な防御戦略は 悪意のある攻撃者がこれらの脆弱性を 悪用する能力に影響を与える。

    私たちは、セキュリティ緩和策と呼ばれる 技術の組み合わせを用いてそれを行います。 そして、緩和策という概念。 失礼ですが、緩和策という 概念自体は新しいものではありません。 それらは過去30~ 40年の間に進化し、存在してきた。 そしてAppleは常に 新しいものを発明し提供しようと努力している。 そして、その多くはあなたの アプリで利用可能です。 そして、それらが安全に 使用できると確信できたときには、 多くの場合、あなたが何もしなくても 自動的にデフォルト設定になっている。

    対策としては、バッファオーバーフローに 対する早期防御策などがある。 clangスタックプロテクターのように、実行不可能な スタックを保護する そしてaslrは完全に カーネル整合性保護などの最新の ハードウェア支援技術へ そして、 Xcode 26 の高速な権限制限があります。 新しい強力なソフトウェアがあります また、アプリを保護するために使用できる ハードウェア支援型の緩和策もあります。

    ポインタ認証は、コンパイラによって 支援されるハードウェア技術である。 あらゆる種類の脆弱性を検出し、 防止することができます。 搾取されることから、 また、たとえエクスプロイトが 発生した場合でも、 アプリのコードフローの整合性が維持されます。

    iPhone 17および iPhone 17 Proで 導入されたメモリ整合性強制機能、 これは5年間の研究の結果であり、 モデリングとエンジニアリング そして、セキュアアロケータによって 提供される堅牢な基盤の上に構築されています。 強化されたメモリタグ付けと相まって、 タグの機密性強制として知られる 拡張機能とセキュリティポリシー。 それはかなりの量で、これらのセッションではさらに 多くのことが語られるでしょう。 それらの緩和策については、 さらに詳しく述べる必要があるでしょう。 後ほど、メモリ整合性の強制とポインタ認証の 導入に関するセッションで説明します。 私の詳しい情報は、security. apple.comのブログで ご覧いただけます。

    Apple はメモリ整合性の強制が メモリ安全性の最も 重要なアップグレードコンシューマー向け オペレーティングシステムの歴史において。

    しかし、まれな状況では、 高度な攻撃者は依然として 到達可能な脆弱性を見つけるそして、 我々の対策にもかかわらず悪用された。

    そのような場合、我々の最終防衛線は 封じ込めと呼ばれる。

    先ほどの連鎖を考えてみましょう。 攻撃者が発見したシナリオでは そして、アプリのメモリ安全性の 脆弱性を悪用した。 彼らは今やそれを完全に支配している。

    理想的な目標は、攻撃者をこのような環境に 閉じ込めることです。 そのため、アプリのデータや プラットフォームのその他の部分には アクセスできません。

    さて、 iPhoneのごく初期の頃から、 アプリはサンドボックス内で実行され、 悪意のあるアクセスを防ぐのに役立ちます。 そしてユーザーデータを保護する。 もちろん、アプリは 自身のデータにアクセスできます。 そして、その電力を供給する システムサービスを利用する。 高度な攻撃者に対して アプリが使用するフレームワーク、 しかし、さらに極端なレベルの 隔離が必要である。 アプリ全体を切断することは 不可能ですこのような システム。 UIを描画するなどの操作を行うには、 アクセス権限が多すぎる。 あるいは、そのような環境で機能するために 必要なリソースにアクセスすること。 そのため、メッセージのようなセキュリティ上重要な アプリでは、 新たなアプローチが必要となる。 そして Safari。 Appleは マルチプロセスアーキテクチャを設計した。 攻撃者から提供された 複雑なデータの処理を移動させる ほとんどアクセスできない、 非常にサンドボックス化された環境へ 他のサービスやカーネルなどのシステムリソースにまで 及ぶ可能性があります。

    その結果、未知の脆弱性のリスクを 移転することができる。 たとえ妥協が成功した場合でも、 攻撃者を資産のない環境に閉じ込める メッセージやクッキーなど。 環境には選択肢を見つける機会もほとんどない 権限を昇格させ、セキュリティを強化した 上でユーザーデータにアクセスする。 Xcode 26では、アプリでもこれらの 機能を利用できます。 これらの厳しく制限された安全な環境のうち、 それらは拡張セキュリティ拡張機能と 呼ばれています。 メッセージアプリが写真を受信した際に、 このアーキテクチャをどのように 利用するかについて説明します。 メッセージアプリでは、これをセキュリティ拡張機能と 呼んでいます。 防爆扉。そして、セキュリティポリシーは シンプルだ。 解析が完了するまでは、受信したすべての アセットを悪意のあるものとして扱う。 そして、原始的な形態に分解されるか、 防爆扉内部で爆発する。 そしてこのポリシーは、 より高い権限を持つメッセージアプリが、 ブラストドアから返される 単純な型を検証するだけでよい。 そして、複雑で危険な解析処理は、 最も低い権限レベルで行われる。

    つまり、メッセージはインターネット経由で メッセージアプリに届き、 解析や処理を試みることなく、それを直接、 その安全な防爆扉内部の防爆扉に送ります。 画像の処理と解析を開始する時が来ました。 攻撃者によって送信された可能性がある。 明らかに、ほとんどの場合、画像は有効です メッセージは潜在的に 複雑な型からそれを変換します 検証可能で、ユーザーに 表示するために使用できる、 はるかにシンプルな形式に変換する。 画像が無効な場合は、エラーが発生します。 メッセージを送ると、 トラフィックが途絶えてしまう。 攻撃者がBlast Doorの脆弱性を 悪用することに成功した場合、 しかし、それらはその2番目の プロセス内に含まれており、 メッセージデータベースやシステムの 他の部分へのアクセス権を持たない。

    そこで、Blast Doorは メッセージに自身のイメージを返す必要がある。 そしてここで覚えておくべき重要なことは、 セキュリティ封じ込め プロセスが侵害される可能性がある。 そのため、そこから送信され、メッセージに 返されるデータはすべて信頼できません。 正常にトランスコードされた 画像である可能性があります。 あるいは、攻撃者の制御下にある完全に 悪意のあるデータである可能性もある。

    そのため、最も重要なことはこの アーキテクチャでは、 メッセージが安全にそして、 受信したデータが適切な形式の画像であることを 安全に検証します。 そして私たちが期待する形式で、 そしてそれは、メモリを安全に 保つという従来の戦略と、 迅速かつ攻撃対象領域の縮小。 その検証を安全に行うために そして、必要最小限のコードのみを公開する。 画像が検証されたら、 そのまま議事録に載せても問題ありません。

    これは、Appleが 封じ込めをどのように 利用しているかを示す一例にすぎません。 セキュリティ上最も機密性の 高いコードベースにおいて。

    最後に、5番目の選択肢はそしてコードから できるだけ多くの脆弱性を排除する 他の戦略を独自に追求しながら、 可能な限りそれを実行する。 それだけでは攻撃を防ぐには不十分です。 しかし、それは最も弱い 部分を見つけるのに効果的である。 そして、攻撃者と同じように、 最も容易に手に入れられる獲物を特定する。

    Appleでは、手作業とそして、 コードの脆弱性を発見するのに 役立つ自動化された技術。 開発中および遡及的に コードの監査を実施します。 また、clangの静的解析器を使用して、 人間のレビューを支援します。 そして、継続的インテグレーションの ワークフローにおいても。 私たちはファジングという技術を利用します。 これはツールが自動的に多くの、 脆弱性を発見しようとして プログラムに多くの入力を与える、 アドレスサニタイザーなどのツール スレッドサニタイザーは、コードの デバッグだけでなく、 開発段階から積極的に 脆弱性を発見することも重要です。 そして、ファジングなどの技術と組み 合わせて使用​​される。

    つまり、Appleがレイヤリングの アプローチについてどのように 考えているかという枠組みがあるということだ。 メモリ安全なコードに。そして、 私が持っているすべてのツールを使用できます。 理想的にはバグを不可能にするために 話したばかりです Swiftのようなメモリ安全な言語を使用する

    攻撃を減らすことで脆弱性をアクセス不能にする 利用可能な表面。 コードに緩和策を適用することで、 脆弱性を悪用可能にしてしまう。

    エクスプロイトによる 被害を封じ込める。拡張セキュリティ拡張機能を 使用することで、 複雑な構文解析を行うため。 そして最後に、 そして、コード内のバグをできるだけ 多く排除する 他の戦略を追求しながら、 可能な限りそうしてください。

    それでは、デヴォンにバトンタッチします。 Appleのセキュリティ関連言語および ツールの開発を統括する人物。 ありがとう。

    ありがとう、マーク。 こんにちは、デボン・コフランです。 私はAppleで開発者向け セキュリティツールグループを率いています。

    Xcodeは厳選された 様々な保護機能を提供します。 アプリに最先端のセキュリティを提供します。 それらの個別の保護機能と、それらを有効にする 方法について詳しく説明します。 そして、それらを組み合わせて 最大限の保護を実現する方法を説明します。

    セキュリティとは、メモリの安全性を 確保するためのトレードオフを適切に 判断することである。 最も重要なトレードオフは セキュリティ上の利点である そして、コードの変更やテストといった エンジニアリング作業も含まれます。

    トレードオフを、縦軸にメリットをとった グラフとして考えてみてください。 そして水平方向への導入の容易さ。

    簡単に適用できる対策もあるが、効果は低い。

    中には難易度は高いが、 より高い安全性を提供するものもある。

    トレードオフをうまく乗り切るには、 最小限の労力で最大限の 効果を得ることが重要だ。 最大の利益を得ながら。

    右上隅が最適な位置です。

    Appleでは、ハードウェア、 オペレーティングシステム、 そして、その最適なポイント付近で 保護を提供するプログラミング言語、 しかも、優れたパフォーマンスを維持しながら。

    例えば、メモリ整合性の強制は 強力なセキュリティを提供する。 導入コストが大幅に削減 ソフトウェアのみの保護よりも 高いパフォーマンスを発揮します。

    保護の4つの異なるクラスについて説明します。

    セキュリティバグを出荷前に 発見するのに役立つバグ検出ツール そして、より強力なセキュリティ対策の 導入に向けた道筋を整える。

    アプリ全体の保護機能により、 アプリ全体のセキュリティが向上します。 多くの場合、ボタンをクリックするだけで 済みます。

    C言語およびC++言語のコード強化、 これにより、既存の安全でないコードベースに 境界安全性を追加することができます。

    そして、完全なメモリ安全性を 提供する Swift。

    これらはマークが説明したのと同じ戦略です。 しかし、これから実際にそれらを実行するために 使用できる技術について説明します。

    マークは、新しいコードベースについて、 保護レベルの高いものから 低いものへと順番に並べた。 そこから始めるべきだ。 アプリ全体を最初から最高レベルで保護します。

    しかしセキュリティを後付けする場合 既に攻撃を受けている既存のアプリに、 今適用できる保護策について 戦略的に考えることが重要です。 それには時間がかかるだろう。

    それらについて話そう 導入が容易な迅速なセキュリティ対策から順に、 非常に強力な保護策だが、 それを実際に実施するにはより 長い時間がかかるだろう。

    私は、あなたがこれらのさまざまなテクノロジーを 使いこなせるようお手伝いします。 そうすることで、アプリのセキュリティを 最大限に高めることができます。

    まずはバグ検出ツールから始めます。

    これらは、リリース済みのアプリで 実行されているアクティブな 保護機能ではありません。 代わりに、それらは構築時に使用されます また、出荷前にバグを見つけるための デバッグ時間も確保できます。 彼らは道を切り開く バグを早期に発見することで、 技術の普及を促進する。

    これらのツールは右下象限に位置します。

    使い方は簡単です。実行するだけで、 すぐに問題の解決に取り掛かれます。

    彼らは対処可能なバグを発見するが、 すべてのバグを発見することはできない。 そのため、これらは 優れた予防策ではありますが、 他の保護策を採用することが極めて重要です。 それについては後で話します。

    良いニュースは、これらのツールを使うことでそれがより 簡単になるということです。

    まず最初に説明する バグ発見ツールは、消毒剤です。

    アプリを再コンパイルします アプリの実行中にバグを見つけるのに 役立つ追加の計測機能を備えています。 これらはC言語系言語とSwiftに 対応しています。

    そして、消毒剤の素晴らしいところは、 誤検出はほとんどありません。 サニタイザーがバグを報告した場合、 それはバグが存在するということです。

    アドレスサニタイザーは、メモリの安全性の バグを追跡することで発見します。 どのメモリ位置が有効で、 どのメモリ位置が無効か。

    マークが指摘したようなバッファオーバーフローを 見つけるのに非常に優れています 先に示し、無料バグの後に使用する、 プログラマーがメモリを 解放したにもかかわらず、 誤ってダングリングポインタを 残してしまった場合。

    ヒープとスタック、そしてグローバル変数における メモリ破損を検出します。

    また、メモリが割り当てられ、 解放された場所のバックトレースも提供します。 バグを迅速に修正するために。

    スレッドサニタイザーは、発生する データ競合を検出します スレッドが干渉する場合 別のスレッドがアクセスするメモリに対して、 両者間の同期が行われていない。

    これは、自動参照カウント方式であっても メモリ破損を引き起こす可能性があります。

    次はclangの静的解析ツールです。

    アプリを実行する必要すらなく、 バグを検出します。 そうではなく、プログラム内で 起こりうる経路をシミュレートする。 つまり、バグを見つけるために テストカバレッジは必要ありません。 しかし、その代償として、 このツールには誤検出が発生する可能性がある。 つまり、実際にはバグがないのに、バグとして 報告する可能性があるということです。 このアナライザーは、 C、 C+ +、 およびObjective-Cを サポートしています。

    バッファオーバーフローを含む 多くのセキュリティ上重要なバグを発見します。 フリーズ後の使用、 初期化されていないメモリの使用、 および安全でないAPIの使用。

    ターゲットのビルド設定でこれらの チェックを有効にしてください 次に、製品メニューから「分析」 を選択してアナライザーを実行します。

    アナライザーがバグを発見すると、 問題の内容と、それが顕在化する 制御フロー経路が表示されます。

    矢印は、バグに至るまで のプログラムパスの各ステップを示しています。 また、注釈では、その道のりにおける 重要な出来事について説明しています。 例えば、使用例において。 解放後、パスはメモリが割り当てられ、 解放された場所を示します。 そして後に使用された。

    これにより、脆弱性を理解し、 修正することが容易になります。

    住所消毒剤、 糸消毒剤Clang静的アナライザーは重要な バグ発見ツールです コード開発を支援するため。 ビルド時とテスト時に使用してください。 彼らはあなたのバグの一部は見つけるだろうが、 すべてを見つけるわけではない。 ランニング。これらのツールは、 ランニングをより簡単にするための 素晴らしい第一歩です。 アプリに、より強力なセキュリティ対策を 導入してください。 そしてはっきり言って、 もっと多くのことが必要だ。 しかし、それらはさらなる 重要な保護措置を追加する道を開くものである。

    次に、アプリ全体の保護について説明します。 これらはアプリ全体のセキュリティ強化の優れた ベースラインレベルを提供します。 コード、ライブラリ、 システムフレームワークなどを含みます。 これらは簡単に追加でき、 セキュリティを大幅に強化します。

    型付きアロケータハードウェア、 アプリ全体の保護の 5 つの種類について説明します。 メモリタグ付け、ポインタ認証、 読み取り専用メモリ、 さらに、セキュリティ機能の 強化も図られています。

    最初の包括的なアプリ保護策は、 型付きアロケータです。

    これは、解放後の利用攻撃から 保護する新しいシステムアロケータです。 右上隅のスイートスポットに近い 位置にあるので、素晴らしいです。

    優れた保護機能を備えており、 導入も非常に簡単です。

    解放後使用バグはメモリ破損の一種です。 プログラムがメモリを割り 当ててからそれを固定する場所、 しかし、誤ってポインターをぶら 下げたままにしてしまう。 解放された記憶の種類は「犠牲者」と呼ばれる。

    攻撃者は、プログラムを操作することで ダングリングポインタを悪用する。 別の型を割り当てる。 同じ場所にいた攻撃者は、 そして、被害者ポインタが攻撃者から データにアクセスするように仕向ける。 まるで被害者タイプのように。 これは型の混同です。 攻撃者が被害者を騙して 退却させることができれば。 攻撃者。攻撃者は ポインタとしてデータを制御した。 意図しないメモリ領域を変更したり、 予期しないコードを呼び 出したりする可能性がある。

    型付きアロケータを使用すると、 コンパイラとオペレーティングシステムは 連携して動作する 異なる型を確率的に割り 当てることで、型の混同を防ぐ 異なるメモリ領域に格納される。

    加害者割り当てにおける被害者は、 おそらく異なるグループに分類されるでしょう。 つまり、攻撃者は型の混同を 利用することはできない。

    素晴らしい投稿があります Apple Security Research Blog で次世代に向けて Xnuのメモリ安全性の このアプローチをカーネルに適用する 方法について、非常に詳細に説明します。

    型付きアロケータを有効にするには。 署名と機能エディターを開いてください。 セキュリティ機能を強化し、 ビルド設定を有効にします。

    今日からオンにしてください。 使用に対する非常に強力な保護を提供します。 無料の脆弱性の後。 チェックボックスをオンにして アプリを再コンパイルするだけで済みます。

    アプリ全体を保護する2つ目の方法は、 ハードウェアメモリのタグ付けです。 バッファオーバーフローや解放後使用バグに 対して非常に強力です。 そしてヒープに割り当てられたメモリ。 これは、型付きアロケータと連携するように 設計されたCPU機能です。 また、カーネルのタグの機密性によって メモリの整合性を強制します。

    iPhone 17、 iPhone Airで利用可能です。 さらに、M5ベースのMacやVision Proにも 対応しています。 ハードウェアメモリのタグ付けは、右上隅の 最適な位置に非常に近い位置にあります。 高い保護性能を持ち、導入も容易です。 しかも、パフォーマンス上のオーバーヘッドを 低く抑えながら。

    メモリ破損を防ぐ仕組みは以下のとおりです。

    型付きアロケータは、各ポインタと各割り 当てにタグを関連付けます。

    CPU はタグとポインターがそして、 記憶の中のタグが一致する。 そうでない場合は、 解放済みメモリ使用バグまたは バッファオーバーフローを示しています。 つまり、ハードウェアは メモリ破損を許容するのではなく、 安全に捕捉する仕組みになっている。

    バッファオーバーフローの例を以下に示します。

    被害者ポインタには、それが指す メモリと一致するタグが付いています。 そして、攻撃者ポインターも同様です。 バッファオーバーランにより、 攻撃者は、攻撃者ポインタを介して 被害者のメモリにオーバーフローする。 しかし、攻撃者ポインタには1つのタグがあり、 被害者メモリには別のタグがあるため、 CPUは不一致を検知し、 攻撃の継続を阻止する。

    メモリタグの不一致により アプリがクラッシュします そのため、メモリタグ付け診断を有効にした 状態で保護テストを有効にする前に また、アドレスサニタイザーと スレッドサニタイザーの下にも、

    次に、メモリの破損箇所を修復します。

    ハードウェアメモリタグ付けを有効にする 方法について詳しくは、 デベロッパで「メモリ整合性強制による アプリのセキュリティ保護」をご覧ください。

    セキュアアロケータとハードウェアメモリタグ付けが 有効になっている場合でも、 メモリ破損のバグの中には、 依然として悪用可能なものもあるだろう。

    アプリ全体を保護する3つ 目の方法は、ポインター認証です。

    ポインタ認証では、ハードウェア、 コンパイラとオペレーティングシステムはすべて 連携して動作します アプリ内の制御の完全性を確保することで、 包括的な防御を提供する。

    iPhone 10 S以降の機種と、 すべてのAppleシリコンMacで 利用可能です。

    制御フローの完全性攻撃では、 攻撃者はメモリ破損を利用して アプリの制御を乗っ取る。

    これは、デベロッパが意図していなかった 予期せぬ状態にプログラムを陥らせる。

    マークが先に説明したスタックバッファオーバーフローを 思い出してください。 攻撃者がパスワードバッファを オーバーフローさせた 近くの関数ポインタを上書きします。

    非常に長いパスワードを入力することで、 攻撃者は関数ポインタの値を変更できる 彼らが望むものなら 何でも。 その後、プログラム内の任意の 関数を呼び出すことができ、 予期せぬ状態につながる。

    ポインター認証を使用。

    CPUはポインタに暗号署名を行う そして、使用前に認証を行います。 ポインタの署名が 期待されるものと一致しない場合、 ハードウェアは予期しないコードを呼び 出すのではなく、安全にトラップします。

    バッファオーバーフローの例では。 これにより、攻撃者が任意の関数を呼び 出すことを防ぐことができます。

    ポインタ認証はメモリ整合性の 強制とうまく調和する 防護のための最終手段として。

    それは、福利厚生の普及状況を示すチャートの 中央にしっかりと位置づけられている。 保護性能は高いが、導入には 多少の手間がかかる可能性がある。 特に複雑なC++コードベースでは、

    だから、アプリを徹底的にテストしてください。 クラッシュが発生しないことを確認するために、 有効化してください。

    型付きアロケータと組み 合わせて使用​​すると最も効果的です ハードウェアメモリタグ付け、 ポインタ認証に取り組む前に、 まずはそれらを採用してください。

    ユニバーサルバイナリの構築が必要 arm64とarm64 eスライスの 両方を持つもの、 ハードウェアサポートのない古いデバイスでも アプリが動作するようにするためです。

    つまり、アプリ内のすべてのライブラリも ユニバーサルライブラリでなければなら ないということです。

    つまり、ベンダーのバイナリライブラリや フレームワークに依存している場合、 依存関係の汎用バージョンを入手するには、 彼らと協力する必要があります。

    4つ目の保護機能は、読み取り 専用のプラットフォームメモリです。

    ダイナミックローダーは、アプリ内の コードを読み込む役割を担います。 そしてそのライブラリ。攻撃者が可能であれば、 非常に魅力的な標的となる。 動的ローダーのメタデータを侵害する、 彼らはそれを使ってあなたのアプリケーションを 完全に制御することができます。

    読み取り専用のプラットフォームメモリは、 攻撃者がそのデータを改ざんすることを 防ぎます。 つまり、それを変更できるのは ダイナミックローダー自体だけです。 これは貴重なセキュリティ保護を提供し、 導入も非常に簡単です。

    ほとんどのアプリは互換性を保つために 変更を加える必要はありません

    互換性を確保するため。 システムAPIを使用して、De WildeおよびObjective-Cランタイムの メタデータを変更します。 それらを直接変更しないでください。

    最後のタイプのアプリ全体 保護とは、 プロセス外拡張セキュリティ拡張機能のことです。

    マークが説明したように、 このアプローチは封じ込めの一形態である。 これは非常に強力なセキュリティ上の 利点をもたらします。 ただし、導入にはある程度の投資が必要となる。

    信頼できないデータを処理する コードを拡張機能に移動することで適用します。

    次に、セキュアシステムXpc APIを 使用して、 メインアプリケーションからデータを 転送します。 拡張機能でその信頼できないデータを処理し、 結果をメインアプリに返し、 必ず検証してください。

    さて、封じ込めは、攻撃者が メモリ破損を利用して拡張機能を侵害する。

    目標は、その攻撃者をプロセス内に 閉じ込めることです。 そのため、彼らはメインアプリケーションの データにアクセスできなくなります。

    導入にあたっては、アプリのどの部分が 信頼できないデータを処理している かを評価してください。

    コードベースをリファクタリングして、 それらの部分を別のプロセスに分離する そして、拡張機能からの応答を検証します。 信用してはいけません。

    これは、他の保護戦略を補完するものです。 それはそれらの代わりにはならない。 したがって、アプリ全体でメモリ整合性の 強制を有効にしてから採用してください。 因数分解には時間がかかる場合があるので。 ポインタ認証と並行して進めてください。

    アプリ全体の保護は、 その対策のほんの一部にすぎません。 または、Xcodeで採用するための手順をいくつか 実行するだけで済みます。 型付きアロケータのハードウェアメモリタグ付け、 ポインタ認証を有効にする。 読み取り専用のプラットフォームメモリ。 強化されたセキュリティ機能を採用することで。

    次に、セキュリティ機能を強化した 拡張機能を作成します。

    これらのアプリ全体保護機能を採用してください アプリ全体に強力なセキュリティの 基準レベルを提供するため。

    それらの保護は素晴らしい、 しかし、アプリに攻撃対象領域がある場合は、 より多くの保護が必要です。 C言語をベースとした言語で。

    ホラップを採用した後、 保護措置はさらに強力なアプローチを適用する 信頼できない入力を処理する、 安全でないコードベースの場合。

    XcodeはC言語と C+ + 言語の両方に対して保護機能を提供します。

    まずはC++から始めます。

    ほとんどのコードベースは、コンテナクラスに 標準ライブラリを使用しています。 その他、広く用いられている抽象概念。

    C+ + 標準ライブラリの強化により、 境界外アクセスから保護されます。 そして、標準のspanやvectorといった クラス。 メモリ破損を許容するのではなく、 安全に捕捉します。

    標準ライブラリを多用するコードベースの場合、 セキュリティ強化は、 セキュリティ導入のトレードオフにおいて、 右下の象限に位置する。 導入が非常に簡単で、 確かな保護機能を提供します。

    さらなる保護のために。 Xcodeの C+ + における バウンドセーフなバッファ使用オプションは、 より強力な保証を提供します。

    このモードでは、コンパイラは 安全でない生ポインタ演算を拒否します。 その代わりに、慣用的なライブラリ抽象化の 使用が必要となる。 標準的なスパン、 文字列、ベクトルなどと同様です。

    このように、コンパイル時の チェックの組み合わせにより 生ポインタ演算とランタイム保護を 防止するため、 さらに、強化された C+ + 標準ライブラリは、 言語に束縛安全性をもたらします。

    さて、 C+ + とは異なり、 Cには次のような高水準言語機能はありません。 使いやすいライブラリ抽象化のための 演算子オーバーロードとして 境界安全なポインタ演算の場合。

    このギャップを埋めるために、 Apple はC 言語用の 新しい言語拡張機能を作成し、 境界安全に直接そして、 この拡張機能を言語標準に 組み込むことを目指している。

    安全なインデックス作成の 仕組みは次のとおりです。 ポインタに値を格納するには、ポインタが 指すメモリの境界に関する情報が必要です。 そのため、安全性を確保するために、 コンパイラはエラーを出してそのインデックスへの アクセスを阻止します。 ポインタの境界を判断できない場合。 その後、注釈に境界を追加できます。 コンパイラに境界を決定する方法を指示する、

    実行時に安全にトラップするために 境界チェックを挿入します 境界外アクセスです。

    このようにして、プログラマが 提供する注釈の組み合わせ また、コンパイラが 生成する実行時境界チェックにより、 境界安全性が確認できるようになります。

    XcodeのCおよび C+ + 境界安全機能には象限の左上隅。 彼らは強力な保証を提供します。 脆弱性のクラス全体を排除し、しかし、 それらはソースコードの変更を必要とします。 アプリ全体の保護機能を既に導入した後に、 これらの保護機能を適用してください。 メモリ整合性の強制など、 最も機密性の高いCおよびC++コードに、 さらにセキュリティを強化するための 仕組みです。

    さて、ここまでは、 私は保護機能を後付けするために 設計されたツールについて話しました 安全でない C、 C+ +、 およびObjective-Cコードベースに 適用される。 これらは強力な保護策であり、 しかし、完全なメモリ安全性を確保するには、 メモリ安全な言語が必要となる。

    Swiftはメモリ安全性が高く、 プラットフォームのセキュリティ保護機能を 活用しています。 OSのハードウェアレベルおよび言語レベルで。

    Swift six two は 新しい軽量ライブラリファミリーを提供します パーサーでの低レベル使用のために 設計された抽象化 その他、セキュリティとパフォーマンスが 極めて重要な場合。

    例えば、新しいspanファミリーの型では、 継続的な非所有メモリへ。

    Spanは完全にメモリセーフです。 高度な機能を使用しています

    そして、ライフタイムとバウンドの 両方を保証するために Swift標準ライブラリを使用します。 安全範囲も速い。 オーバーヘッドゼロの実行時オーバーヘッドを 保証する必要がある場合には最適です。 生涯にわたる安全性と高度に 最適化された境界チェックを実現します。

    Swift Span では、 コンパイル時のチェックと生涯安全性の 組み合わせにより また、実行時に境界安全性を チェックすることで、 セキュリティと低オーバーヘッドの 両方を実現できます。

    アプリを保護するための戦略は2つあります。 Swiftが新しいコードを採用したことで そして、既存のセキュリティ上重要な コードを書き換えること。

    両方の戦略を活用しましょう。

    Swiftを使えば、メモリ安全な コードを簡単に書くことができます。

    まだSwiftで新しいコードを書いていないなら、 今すぐ始めましょう。

    今日あなたが書くコードは、 将来攻撃者が標的にするものになるでしょう。 だから、新しい機能は Swiftで書きましょう。 既存のサブシステムをリファクタリングまたは 近代化する場合、 その機会に、それらも Swiftで書いてみてください。

    セキュリティ対策に関しては、 機会を捉えたリファクタリングを 待つべきではありません。 代わりに、それらのコンポーネントをSwiftで 積極的に書き直してください。

    最も重要な焦点領域はパーサーです。 特にメディアやプロトコルに関して。 複雑な状態機械。 オブジェクト、ライフサイクル、 および信頼できない入力を処理するあらゆるものを 制御する。

    これで、悪意のある攻撃者から アプリを保護する方法がわかりました。

    これらは、Appleが自社アプリに 使用しているのと同じ保護措置です。 重ね合わせる際に丁寧に作られている そして、コードベースの重要な 箇所に適用されます。 彼らは最高レベルのセキュリティを提供します。

    これらを採用するには、 メモリの整合性を含むXcodeの セキュリティ強化を有効にします。 強制、およびポインタ認証、 アプリ全体に最低限の保護レベルを 提供するため。

    信頼できない入力の処理と強化された セキュリティ拡張機能を含みます。 そして、バインドセーフティ拡張機能を 使用して、 安全でないCおよび C+ + コードベースを保護します。

    そして、すべての新しいコードには 完全にメモリ安全なSwiftを使用し、 そして、セキュリティ対象領域の 標的を絞った書き換え。

    セキュリティは今、 これまで以上に重要になっている。 アプリとユーザーを保護するために、 今日これらの手順を実行してください。 そして、彼らの機密データ。 ありがとうございます。

    デビンとマーク、 素晴らしい概要説明をありがとう。 それでは、少し休憩を取りましょう。 太平洋時間11時25分に、ビッグサーの 会場とオンラインで、ぜひご参加ください。

    良い休暇を過ごされたことを願っています。 そして、ここに直接お越しいただいた皆様には、 お話する機会があったことを願っています。 他の開発者たちと共に。

    次のプレゼンテーションでは、 ハードウェアのユニークな組み 合わせについて説明します。 そしてソフトウェアセキュリティ。 この作品は素晴らしいと思いますし、 あなたもきっとそう思うでしょう。 エンリコを温かく迎えましょう。

    ありがとう。

    こんにちは。ようこそ。

    本日最初のディープダイブへようこそ。 私の名前はヘンリー・カペルです。 私はセキュリティエンジニアで、 後ほど同僚たちもステージに上がります。 フィリッポとオリバー・ハント。 これから、当社の最も魅力的なセキュリティ機能のうち 2つをご紹介します。 メモリの整合性、強制、およびポインタ認証。 これは上級者向けの講演になります。 今回は、メモリ割り当て、ポインタ、 そしてセキュリティモデルについて説明します。 まず、長さについて 理解していただくことから始めます。 メモリ整合性の強制は、 アプリケーションを保護するために行われます。 するとフィリッポがやり方を教えてくれます 特定のカスタムメモリ管理実装に対応するため セキュリティアプリケーションの動作を 妨げたり、 そもそも機能しなかったりする可能性がある。 誠実性の徹底を忘れないでください。 それでは話題を変えましょう そして、オリバーが登壇し、当社のセキュリティ戦略の 別の側面について解説します。 ポインター認証の使用方法 攻撃者が任意のコード実行を 行うことを防ぐため。

    しかし、 自己紹介はこれくらいにしておきましょう。 まずはメモリ整合性の強制から始めましょう。 先に述べたように、セキュリティ問題の大部分は メモリに関するものです。 メモリ整合性強制におけるデータ破損バグ。 私たちの使命は、これらの資源の大部分を 有効活用できるようにすることです。 これは非常に大きなことです。それらはもはやあなたのアプリケーションにとって セキュリティ上の問題ではなくなります。

    メモリ整合性強制機能は、 私たちがそれを使用するのとまったく 同じ方法でリリースされます。 私たち自身のためだ。 ここでは、それは彼の妨げにはならない。 それは、ファーストパーティアプリがまた、 サードパーティ製アプリも、ユーザーの 安全を守る上で同様に重要です。 そのため、私たちは始めるための素晴らしい リソースをいくつかまとめました。 メモリ整合性の強制機能付き。 セキュリティのすべての軸について 説明するブログを公開します メモリ整合性強制が動作する仕組み。

    技術講演では、その方法を段階的に説明します。 アプリケーションにメモリ整合性の 強制機能を組み込む。

    そして私たちは素晴らしい終わりもまとめました ほぼ同じテーマに関する ドキュメントを締めくくる。 メモを取る必要はありません。 これらのリンクはすべてメールでお送りします。 後で視聴する場合でも、 それらはオンラインセッションに添付されます。 ぜひチェックしてみてください。 素晴らしいですよ。今日は 詳しい紹介はしませんが。 メモリ整合性の強制に関して。 そして私は、アプリケーションにのみ 集中します。 セキュリティの中核部分と連携し、 メモリを活用する 型認識型セキュアメモリ割り当て器 タグ付け拡張機能。

    MTVはハードウェア技術である そして、メモリ整合性の強制を支える 最大の投資の一つは、 そして、おそらくこのアプリケーションの中で 最も目に見える効果をもたら すものと言えるでしょう。 それでは、簡単に見ていきましょう。 これは鍵と錠のシステムです。 メモリへのロックは 16バイト単位で割り当てられます。 それはページよりもはるかに細かい粒度だ。 そして、これは動的な割り 当てには理想的な方法と言えるでしょう。 キーは代わりにポインタに格納されます。 上位ビット、ロック、 キーは一般的にタグと呼ばれます。 したがって、メモリタグ付け ソフトウェアという名称は、 タグの割り当てを制御するものです。 それが、いわゆるタグ付けポリシーです。 画像では、黄色のバッファタグ7は ソフトウェアの決定です。 そして2つのポインタも同様です 左側のハードウェアでは、 代わりにチェックポリシーと呼ばれるものを 実装しています。 鍵と錠が一致する 場合にのみアクセスを許可する。 ポインタにタグが付くようになったとしても、

    これらはソフトウェアにそれほど 大きな影響を与えません。 実際、どの記憶においても、 整合性の維持は極めて単純明快である。 Xcodeを数回クリックするだけです。 他の技術とは異なり、 導入には相当な労力が必要となる。 そして私の作品は、例外を除いて、 ほとんどが未修正のソフトウェア上で 制作されています。 つまり、何か裏があるはずだそうでなければ、 私たちは今日ここにいなかったでしょうただし、 アプリケーションが独自のメモリ管理を 実装している場合は除きます。 この話題についてはこれまで 何度か触れてきましたが、 ではそれが何を意味するのかを 改めて説明しましょう。 アプリケーションには3つのパターンがあります これにより、カスタムメモリ管理が 可能になります。 ここでは、可能性の高い 順にそれらを使用します。

    1つ目は割り当てられたラッパーです。 割り当て済みラッパーは、 システム割り当て済み APIをラップするインターフェースです。 そして、通常は携帯性の理由からそうする。 あるいは、メモリ操作に関する 追加のロジックを実装する必要があるでしょう。

    これらは圧倒的に 最もよく見られる構造物である。 そして、これから説明する 他の2つのケースとは正反対です。 この考え方をより分かりやすくするために、 簡単な例を挙げましょう。 ここでは、メモリを割り 当てる関数を定義します。 これは実際にmallocを呼び出すものです。

    残りのコードは、malloc ディレクトリを 呼び出します。 しかし、代わりに常にこのインターフェースに 移動します。 この例に注目してみましょう。 フィリッポは短い時間でステージに上がり、 それについて詳しく説明します。

    2つ目の直接的なメモリマッチングパターンは、 プーリングとキャッシング戦略です。 これらの戦略の目標は 頻繁に使用される物品をリサイクルすることで パフォーマンスを向上させる、 システムアロケータへの往復通信を 回避するためです。 それらもそれなりに一般的だが、 アロケータラッパーほどではない。

    そして最後に、幸いなことに、 アプリケーションでは非常にまれなことですが、 しかし、フレームワークではより一般的である これらは完全にカスタマイズ可能な メモリ割り当て器です。 この場合は、そのまま 交換できる部品があります。 これはシステムデフォルトのものを 完全にバイパスします。

    直感的に、これら 3つのパターンはすべて有害である メモリタグ付けの整合性強制の セキュリティに干渉するため または、システムアロケータを 完全にバイパスする。 そして、当然のことながら、 本日の重要な推奨事項は以下のとおりです。

    デフォルトのシステムアロケータを使用します。 もう少しこのスライドに留まります。 ラッパーやキャッシュなしで デフォルトのシステムアロケータを使用します。 あるいは、カスタム実装も可能です。 拡張性を高めるために 多くの時間を費やしています そして大多数のユーザーにとって高速で、 そして、過去3年間でゼロから再実装された。 つまり、3年以上前の業績数値を参考にすると、 それらを再評価してください。 きっと嬉しい驚きがあるでしょう。 そして、私たちはそれを書き直し、 誠実性の確保において際立つようにしました。 もちろん、抽象化の中には存在する 正当な理由があるものもあります。 もしかしたら、古いコードがまだかろうじて 動いているだけなのかもしれません。 そして、それを引き 継いでいかなければならない。 それでいいんです。だから この講演の残りの部分では、 それらをどのように維持できるかを 見ていきましょう。 しかし、そのためには 当社のアロケーターが満たしている 極めて高いセキュリティ基準を満たすため。 そのためには、なぜ私たちがそのように 設計したのかを理解する必要があります。 つまり、セキュリティについて 理解する必要があるということです その背後にある科学的根拠。

    では、攻撃者が何をするのか、つまり システムを悪用することから始めましょう。 そして、きっと共感を呼ぶであろう何かと共に そして、この話題について皆さんに 少しでも分かりやすく説明したいと思います。

    エクスプロイトを作成するのは、 デバッグの逆の作業である。

    メモリ破損の問題をデバッグする際は、 犯罪現場から始まり、 誤って改変された記憶へと至る あるいは、誤って使用された結果、 プログラムが誤動作するようになった。 原因を突き止めるために 断片をつなぎ合わせようとするが、 バグは何だったのか? メモリのどの部分が破損していたのか? 起源は?

    搾取においては、全く逆のことが起こります。 メモリから開始しますが、 その処理が間違っています。 そして、変更を加えている メモリを探そうとします。

    もっと科学的に言うと、 私たちは業界では少し独特な アプローチをとっています。 そして実際、それは 攻撃者中心の設計になっている。

    我々には、攻撃者型と呼ばれる記憶が一つある。 これが腐敗を生み出している原因だ。 ここでいう「タイプ」という用語は、 多くの役割を果たします。 メモリ位置の固有の特性を指します。 それはデータ構造かもしれない。 それは文字列かもしれないし、 レコードの集合体かもしれない。 次に、被害者タイプがあります。 それは攻撃者にとって 改ざんする価値のあるメモリだ。 それがメモリ破損の標的です。 メモリにはパスワード、関数ポインタ、 あるいは、後々攻撃者に能力を与えるもの 任意のコードを実行する。

    これら2種類のデータは、 メモリ上のどこかに存在する。 つまり、両者の間には 一定の距離が存在するということだ。 患者がいる場合、距離は1となる。 あるいは、それらが重なり合う場合もあり、 その場合は距離はゼロとなる。

    攻撃者がシステムを監視できると仮定します そして、任意の数の演算を実行します。 カーネルと通信したり、 ファイルシステムを調べたり、 特権によって許されることなら何でも。 私たちは攻撃者の行動に 上限を設けることに頼っていません。

    攻撃側がコントロールすれば勝利する そして、加害者から 被害者までの距離を予測する。 以上です。それが、書き込みメモリ、 つまりデータ破損の悪用に関する本質です。

    これは単純に思えるかもしれないが、 まあ、優れた科学とは大抵単純なものだ。 しかし、それは実は非常に奥深いものなのです。 そこに着くまでには長い時間がかかった。 そしてそれは、私たちの選択肢を 明確にする上で重要です。 メモリ破損に対する防御に関しては。 そしてそれは、私たちが 実際に引くことができるレバーは 2種類しかないことを示している そして、守備側の視点からの距離感も重要だ。 ゲーム全体は、タイプ選択と距離を不可能にすることを 目的としています。 あるいは、攻撃者にとって 予測や制​​御が極めて困難である。 これが、当社のセキュアメモリ割り当て ツールがすべて実装している理由です。 4つの主要なセキュリティ特性。

    まず第一に、それらはタイプを認識します。 従来、メモリ割り当ては mallocを用いて行われてきた。 単なるバイト列の羅列では、 要求されたサイズ以上の情報は得られません。 割り当ての意図については認識していない。 代わりに、当社のセキュアアロケータは 型を理解します。 そしてこの大きなレバレッジは、手動入力と、 主にカーネルとコンパイル時の 自動型付けで使用され、 これは、ユーザー空間で 私たちが使用するものです。 型情報が手に入ったら、ゲームを開始できます。 当社のアロケータは、攻撃者が 制御するのが困難になるように設計できます。 メモリ内で型を異なる 領域に分割することができます。 また、種類がたくさんあるので、種類ごとに 1つの地域を設けることはできません。 それは理想的でしょう。 そこで私たちは、似たような特徴を 持つものをまとめて集めるのです。 ブート時にそれらのコレクションを ランダム化します そのため、デバイスごとにグループが異なり、 これにより、攻撃者はエクスプロイトを微調整する 方法を見つけざるを得なくなる。 それぞれの異なる組み合わせについて、 デバイス上で実行した。

    ほぼ同じように、 これらのタイプの領域のメモリ上の 配置をランダム化します。 これもまた、起動時に行います。 そこで、デバイス間でさらにばらつきが 生じることになる。 これにより、攻撃者の試みは再び阻止される。 異なるタイプクラス間の距離を予測する。

    そして最後に、 メモリタグ付け拡張機能を活用します 様々な型クラス内での攻撃を阻止するため。 各場所に異なるタグを割り 当て、 Freecycle、 そして、地域全体にタグが均等に 分布するようにする。また、私たちは 禁止事項も実施します。 隣接する 2 つのオブジェクトが 同じタグを持っているか、 または同じタグを持っています。 これにより、1と小型サイズの間のあらゆる 距離を悪用することが不可能になる。

    これが、メモリ破損バグを防止するための セキュリティアロケータの動作原理です。

    それでは、フィリッポに ステージをお渡しします。 誰があなたのできることをカバーするのか 3つの一般的なカスタムメモリ管理パターンを 防止する 先ほどお話しした通りです。 つまり、それらはアプリケーションのセキュリティを 阻害しないということです。

    次はあなたの番です。

    ありがとうございます。私の 名前はフィリッポで、 セキュリティエンジニアです。今ここにあります。 エンリコが言ったように、 ほとんどの場合、メモリ整合性強制の採用には、 そちら側でコードの変更はありますか?

    しかし、特別な配慮が 必要となる状況もいくつか存在する。 そして、まさにこれから私が説明していくのは、 これらの点についてです。 それぞれが記憶、整合性、 執行にどのように影響するかを見ていきます。 また、そのセキュリティモデルについても 説明し、最適な解決策についても解説する。

    それではまず見ていきましょう おそらく最も一般的に見られる抽象化において あらゆる種類のコードベース、 アロケータラッパー。

    それでは、エンリコが先ほど示した 例を取り上げて、それを見ていきましょう。 メモリ割り当て機能、 これにより、探すべき 機能のセットを定義する機会が得られます。 コードベース内のアロケータラッパーを 特定する。

    まず、ラッパーとは、 ロジックを追加する関数です。 システムアロケータAPI。これらは、 使用されているメモリを要求することを 可能にするという意味で汎用的です。 さまざまな種類のものを保管するために、 そしてそれらはコードベース全体で 抽象化レイヤーとして使用されます アロケータとやり取りする。

    ここまでは、ごく 無害なことのように思えますよね? では、型分離が実際にどのように 機能するのかを見ていきましょう。 アロケータラッパーのセキュリティ上の 影響を理解するため。

    ここに、パケット処理ロジックを 実装するコード群があります。

    ご心配なく、これを全部読む必要はありません。 そして実際、システムアロケータインターフェースへの 呼び出し側に 焦点を当ててみましょう。

    ここに型分離の基礎がある。 そして実際には、コンパイラがすべての 作業を代行してくれているのです。

    Xcodeで型アロケータの サポートを有効にすると、 型メモリ操作と呼ばれる コンパイラ機能を有効にします。 この機能を搭載しているため、 コンパイラは自動的に型を推論します 各割り当てコードサイトについてそして、 各呼び出しを型認識型の呼び出しに書き換え、 型情報を追加の引数として渡す。

    コンパイラが各割り当てに異なる 形状を割り当てる様子を想像してみてください。 そしてこれらの形状は、 まさに伝達される情報を表しています システムアロケータへ、 これは、場所に基づいて 隔離するために使用します。 スタイルバケットポリシーを 実装することにより、 それらのタイプに基づいて分類します。 ラッパーを実装すると、この呼び出し 箇所はコンパイラにとって不透明になります。 これは単一の形状しか認識できないでしょう。 これで、すべての割り当てが システムアロケータによってまとめて バケット化されます。 生成された型情報のみを参照するため ラッパー内の呼び出し箇所で。

    それでは、この問題に対処するために 何ができるか考えてみましょう。

    もちろん、ラッパーによって 実装されるロジックが重要でない場合 コードの機能性に関して、 最も簡単な解決策は、 ラッパーを完全に削除することです。 そして、システムアロケータのインターフェースを 直接呼び出します。

    包装紙を保管する必要がある場合は、 型認識バリアントを適切に実装できます 型情報を転送する 型メモリ操作を採用することにより、 システムアロケータに。 オペレーティングシステム全体で使用されている ものと同じコンパイラ技術。

    それでは、そのプロセスを 段階的に見ていきましょう。

    まず、ラッパーのバリアントの型を宣言します。 これは、サイズ引数の直後に 型ID引数を追加します。

    次に、アンダースコアを使用して型指定されていない バリアントに注釈を付けます。 malloc型マクロは、 対応する型バリアントを指定することによって 作成されます。 そして、サイズ引数の位置。 コンパイラに、すべての呼び 出しを型指定のないバリアントに 変換するように指示しています。 型認識型への呼び出しに、 また、各呼び出し箇所で型記述子を合成する。

    最後に、型認識型のバリアントを 実装する必要があります。 しかし、これは非常に簡単です。 追加したロジックはすべてそのまま 維持できます。 必要な変更は、適切な型を 呼び出すことだけです。 取得した型記述子の値を転送することで、 malloc インターフェースを認識します 議論として。

    この方法では、何も変更する必要はありません 実際にラッパーを使用しているコードへ。 コンパイラは、各呼び出し 箇所で型情報を自動的に提供します。 あなたのために。

    これは簡単な概要にすぎません。 より詳細な情報については、 この手法について解説した 資料をご覧になることをお勧めします。

    よし。これでアロケータラッパーの 扱い方が理解できた。 それでは次に、プールとキャッシュについて 見ていきましょう。

    プールについて話すとき、 私たちは、何らかの形のリサイクルを実施するすべての アプローチを指します。 往復を避けるために同じ種類のオブジェクト システムアロケータへ、 そのような物品が廃棄され、 その後再び使用されるたびに。 キャッシング戦略もこのカテゴリーに 当てはまります。

    この文脈では、重要な概念は 理解すべきことは、これらの抽象化が 人生を変えるということだ リサイクルされる物のサイクル、

    そしてこれは、セキュリティに 関して深刻な影響を及ぼす。 メモリタグ付けによって提供される 保護機能に関して。 それでは、例を挙げながら、 それらの意味合いについて説明しましょう。

    ここにオブジェクトのプールがあります。 それぞれは、メモリタグ付けを使用してタグ付けされた 割り当てによって裏付けられています。

    プールからオブジェクトを取り出すと、 通常はそのオブジェクトへの ポインタを取得します。 これは、割り当てに関連付けられた メモリと同じタグを持ちます。

    対象物を使い終わったら、 それをプールに戻します。 ここで、コードにバグがある 場合を考えてみましょう。 そして、そのオブジェクトへのダングリングポインタを 保持しておく。 これはまさに、攻撃者が 悪用できる脆弱性を無料で提供する。

    もし私たちが単にその物を リサイクルするだけなら。 これは、ダングリングポインターが そして、新しいライトにも 有効なタグが付いています。 ダングリングポインタを制御できる攻撃者は、 リサイクルされた後に オブジェクトを修正するために、 メモリ破損を引き起こし、アプリのロジックが 変わってしまう可能性があります。

    割り当てをそのような脆弱性から 保護するためには、 オブジェクトがリサイクルされる前に、 タグを更新する必要があります。

    再タグ付け後、古いポインタを使用して 実行されるアクセスはすべて 古いタグは安全にエラー処理を行い、 アプリを終了させて​​悪用を防ぎます。

    それでは、それを実際にどのように 実現できるかについて説明しましょう。

    弊社は、パケット処理コードに リサイクルポリシーを実装しました。 パケットを割り当てる必要がある場合、 まず、私たちが管理している スレッドローカルキューから それを抽出します。 そして、リリースバケット関数に 補充します物を処分するとき。 お分かりのように、このアプローチは まさに今見た問題と同じです。 では、MTAが提供する保護措置を維持するために、 私たちは何ができるでしょうか?

    もちろん、もうお気づきかもしれませんね。 最善の解決策は、やはり システムアロケータを直接使用することです。 これにより、すべての割り当てが適切に 再タグ付けされることが保証されます。 メモリに期待される保護機能を提供します 倫理規範の徹底。

    私たちは何年もかけて設計しました そして、安全かつ安全なシステムアロケータを 実装する そして、それはあらゆるシナリオにおいて従来の 割り当て方式よりも優れた性能を発揮します。 そして実際、スレッドローカルキャッシュを 使用すると、 当社のシステムアロケータは、 このようなシナリオにも最適化されています。

    この方法があなたに 適さない稀なケースもあります。 コードのプロファイリングを 行うことをお勧めします。 そして、生活を変えないさまざまな 戦略を探求する 物体の循環。 例えば、使用するオブジェクトを バッチ処理で割り当てるなどです。

    よし、この方法だと非常に簡単だ プーリング戦略を適応させるMIが 提供するセキュリティ特性を維持するため。

    それでは、カスタムアロケータについて 少しお話ししたいと思います。 これは必ずしもアプリケーションコードに 実装されているとは限りません。 しかし、それらはあなたが使用している 外部依存関係の一部である可能性があります。 ライブラリは歴史的にパフォーマンス上の 理由からこれらを実装してきた あるいは、プラットフォーム間の 互換性を確保するため。

    カスタムアロケータが存在する場合、 何が起こるか予測不能となる。 使用するコードを理解するのが非常に重要です カスタムアロケータは Ma の利点を得られず、特に、 アプリは型分離の保護の恩恵を 受けることができません そしてメモリタグ付け。

    このようなシナリオでは、セキュリティを真剣に 評価する必要があります。 こうした実装を維持し続けることの意味合い。 つまり、私たちの提案が 何になるかはもうお分かりでしょう。

    そのコードを、システムアロケータを 直接使用するように移行してください。 私たちは、それがアプリのセキュリティにとって 不可欠な基礎要素であると確信しています。 しかし、私たちは、 カスタムアロケータの使用をやめましょう。

    そのため、26.1以降、 すべてのプラットフォームで、 SDKには、必要なすべての 構成要素が含まれています。 カスタムアロケータにMTの サポートを実装する。

    それでは、それらを一つずつ見ていきましょう。 しかし、各アロケータの実装にはそれぞれ 独自の特性があるため、 理解するのはあなた次第です これらの構成要素を、 ご自身のユースケースで活用してください。

    まず最初に、実行時に emptyが有効になっているかどうかを 確認する必要があります。 そして、ここに示されているように、 OSのセキュリティ設定APIを使用してこれを 行うことができます。 ハードウェアメモリタグを有効にした後、 アプリは、それをサポートするデバイスでは 空のオプションを有効にして実行されます。 しかし、同じコードは、 空のデータをサポートしていない デバイスでも実行する必要があります。 依存するすべての操作空の 命令セットアーキテクチャでは、 プロセス内で実際に空の状態が 有効になっていることを確認した後。

    次に、アロケータが使用する メモリページを割り当てると、 VMにメモリタグ付けをサポートする ページを提供するように 要求する必要があります。 VMフラグをバイパスする。 VM割り当て呼び出しで 空のフラグを使用します。 この段階で、カーネルはページを提供します。 関連付けられたタグはすべてゼロになります。

    そしてそれが理由です。 最後に、そして最も重要なことですが、 位置情報にタグを付ける必要があります。 いくつか異なる可能性が 考えられますタグ付け方式を選ぶ際には、 そして考慮すべき多くの ニュアンスがあるだろうこれらをそれぞれ 実装する際に。

    利用可能なAPIの概要を簡単にご説明します。 各場所にタグを付け直すという 簡単な例を考えてみましょう。 それが解放されて、 私たちのアロケータに戻されるとき。

    タグ付けと割り当てに関しては、 2つの部分があります。 ターゲットを選択し、ポインタに含める そして、そのタグをタグ保存メモリに保存する。 タグを選択する最初のステップは、 除外マスクを生成することです。 現在割り当てに関連付けられている ターゲットに対して。 これにより、ハードウェアに 問い合わせることができます 以前使用したタグを除外して、 新しいランダムなタグを生成します。 空です。ランダムなタグを生成すると、 ポインタが返されます。 同じメモリ領域に書き込むが、 上位ビットに異なるランダムなタグを付ける。

    最後に、空のストアタグを使用して ハードウェアに問い合わせます。 新しく生成されたタグをタグストレージメモリに 保存するには、 新しいタグが付いたポインター そして、タグ付けが必要な基となる メモリブロックのサイズ。 アロケータでメモリにタグを付けるために 必要なのは、これだけです。

    以上が、サポートを実装するために 必要な基本的なツールです。 メモリ割り当て器における メモリタグ付けのため。

    これで、ミラノでの旅は終わりです。 しかし、結論を出す前に、 このセクションの重要なポイントを 改めて述べておきます。 そして、メモリ整合性の強制を最大限に 活用するためにできること。

    ハードウェアメモリのタグ付けを 有効にする必要があります そして、Typekitアロケータのサポートを ユーザーに最も具体的な保護を提供するため 授業で使用するテクノロジー。 メモリ破損の脆弱性を軽減する場合。 導入はとても簡単です。 特に、大多数のシナリオでは、 これらの技術によって 得られるセキュリティ上のメリットをすべて 享受できますコードに 一切変更を加えることなく提供できます。

    しかし、この講演で見てきたように、 保護効果を低下させる特定のパターンが存在する メモリ整合性強制機能によって提供されます。 コードベースを監査し、それらを特定することを お勧めします。そうすることで、 リスクへの曝露状況をより 適切に評価できるようになります。

    これらのいずれかを特定したとき。 好ましい。解決策としては移行すべきである。 システムアロケータを直接使用する。

    これはまさに、あらゆる面で 最高のものを手に入れることができる。

    しかし、時としてこれが実行不可能な場合、 私たちはあなたにツールを提供しました そして、そのような抽象化を 適応させる必要があるという 理解メモリ、整合性、 深く根付いたセキュリティ特性を執行し、 維持するオペレーティングシステムに 組み込む。

    それでは、オリバーをステージにお招きして、 制御フローの完全性についてお話いただきます。 ポインター認証付き。

    ありがとう、フィリッポ。皆さん、こんにちは。 私はオリバー・ハントです。セキュリティと ツール開発を担当するエンジニアです。 Apple社内のセキュリティツールと コンパイラ。 セッションのこの時点で、 メモリ安全性のエラーから コードを保護する方法について学びました。 メモリの整合性を維持したまま。 執行。MI はメモリ安全性のバグを 悪用することを非常に困難にし、 しかし、あらゆる攻撃から 身を守ることはできない。 ハードウェアを導入する方法をご紹介します。 アプリケーションに提供するポインタ認証 制御フローの完全性を維持した上で。 つまり、攻撃者が私を迂回して 任意のメモリを破壊できたとしても、 彼らにはまだ能力がない アプリケーションが実行するコードを制御する ポインター認証付き。 ハードウェア、コンパイラ、 そしてオペレーティングシステムもすべて 連携して動作します 攻撃者が標的とするポインタの有効性を確保する アプリケーションを乗っ取ろうとしたとき。 仕組みはこうです。 ボンネットの下では、

    ポインター認証を使用する場合、 CPUとオペレーティングシステムは ポインタの暗号署名を作成し、 そして、それらの署名をポインタ自体に 埋め込むのです。 これらの署名により、ハードウェアは ポインタの有効性をチェックできる。 使用される前に、コードに 信頼の連鎖を与えるポインタが 使用される時点の値を、 過去まで遡ってリンクする元の価値に、 そして

    ポインタ認証はこれらのポインタを 保護し続けます Miiを使用しているアプリケーションでも。 メモリタグ付け拡張機能。 署名を透明に調整することで 既存のタグに対応するための認証操作、 追加タグ。

    これらすべてが整った状態で、 攻撃者がポインタを改ざんしようとすると、 署名はもはや有効ではなく、 信頼関係は断ち切られた。

    さて、後でコードがそのポインタを 使用しようとすると、 ハードウェアがこれを検知し、 アプリケーションを安全に停止します。 攻撃者は悪意のある コードを実行する前に阻止されました。

    Appleでは、ポインター認証APIを 開発してきました。 ほぼ10年間、私たちはそれをプラットフォームの 予測ツールとして使用してきました その間ずっと。 そして、その設計は安定性と堅牢性を備えている ため、採用することが可能です。 そして、私たちが使用しているのと全く同じ保護機能をあなたの コードにも採用してください。 自社ソフトウェアを保護するため。

    ポインタ認証は大きな変化をもたら すがコード生成に 関しては、アプリケーションに何らかの差異が 生じる可能性のある箇所。

    それでは、主要なものを見ていきましょう。

    返信先住所は長年攻撃者の標的となっており、 そして長年にわたり、 さまざまな緩和策が実施されてきた。 ポインタ認証でそれらを保護する。 これはさらに上のレベルへと引き上げられる。 電話をかけるたびに、 ポインタ認証付きの返信先アドレスがあります。 返信先住所自体と、現在のコールフレームに 関する情報も含まれています。 返信先住所に埋め 込まれている署名に反映させる。 この情報はその後も使用されます 返信先アドレスを追跡する前に、 そのアドレスを認証する必要があります。

    これにより、返還の瞬間から 信頼の連鎖が維持されます アドレスが最初に記録され、 使用される時点まで、 さらに、攻撃者が有効な署名を 再利用することも防ぎます。 前回の呼び出しからのポインタ。

    そしてこれらすべては、基本的な呼び 出し規約の一部として発生します。 また、アセンブリ言語で 記述された関数からは、ほとんど見えない。

    さて、コードが相互作用する 場合関数呼び出しの基本を超えた コールスタックでは、また、 すべてのAPIがそして、 これを行うために 使用しているコンパイラ機能は、 スムーズに動作する。

    それでは、実際に使用している 機能について見ていきましょう。 アプリケーションの動的な制御フローのため。

    まずは関数ポインタから始めましょう。 これらは動的制御フローの最も 基本的な形態であるため アプリケーションには、あらゆる 種類の最も制限のない Cや C+ + などの言語における 間接的なコード実行の一形態。 だから、必ず署名してもらうようにしています。

    これはC言語における 一般的な慣用表現として重要である。 C+ + では、関数ポインタを整数または 不透明ポインタにキャストします。 そして、私たちはあなたが常にこれを避けられるとは 限らないことを知っています。 そのため、ポインタ認証を確実に行いました モデルは、これらのすべての操作を通じて 埋め込み署名を維持します。 コードを変更する必要はありません。

    これは、信頼の連鎖が再び 維持されることを意味する。 攻撃者がこれらのポインタを変更できる ポイントは存在せず、 コンパイラはそれらが関数であることさえ 認識しなくなるかもしれないが ポインタ。

    しかし、あなたのコードでは、 関数ポインタを使ってすべてを行う。つまり、 言語がサポートする動的ディスパッチを幅広く 活用しているということですね。

    そしてそれは、Swiftの仮想メソッドで finalでないメソッドを呼び出す場合です。 C+ + でのメッセージ送信、または Objective-Cでのメッセージ送信など、 あらゆる言語に対応しています。 動的ディスパッチは、複数の間接参照層の 上に構築されています。

    最も単純な形では、 各オブジェクトインスタンスは、何らかの 型情報へのポインターを持っている。 またはメソッドテーブル。

    そしてそのデータ構造には別のポインタがあり、 各手法の実際の実装について。

    この相互作用は、間接的なアプローチが 攻撃者にとって魅力的である。 なぜなら、これらの各層はそれぞれ 独立して攻撃できるからである。

    そのため、 Swift、 C+ +、 そして、 この一連のプロセスにおける各段階で、 Objective-Cは保護されていました。

    このチェーン内の各ポインタの 署名を作成すると、 オブジェクトの種類、 ID、 あるいは、オブジェクトの位置、 さらにはターゲットメソッドの 種類なども含まれます。

    そして、動的な呼び出しを行うと、 各ステップは同じ情報を使用して認証されます。

    この作業をすべて行うことで、 私たちは、あなたのアプリケーションが 保護されていることを確認しました。 メモリ破損だけでなく、ライフタイムや 型の混同攻撃からも影響を受ける。

    しかし、このレベルの保護は ポインターが認証にはコードの変更が 必要になる場合があります。

    その理由を理解するために、まずは 最初の認証ステップに注目してみましょう。

    オブジェクトの位置を各署名に組み込むことで、 署名はこの場所でのみ 有効であることを確認済みです。 メモリ内のメモリ安全性エラーを利用して 攻撃者が攻撃するのを防ぐある オブジェクトを別のオブジェクトの上に コピーする。

    しかし、Memcpyのような低レベル関数を 使用してこれらのオブジェクトをコピーすると、 それは攻撃者がやっていることと 根本的に何ら変わりません。 そして結果は同じになるだろう。 オブジェクトを使用しようとすると、 認証エラーが発生します。

    これはポインタ認証が 変更されるケースの1つです 既存のコードが未定義になるのを防ぎ、 一見正常に動作するように見える動作が、 実行時に失敗する未定義の動作に変化する。

    ここまで、最高レベルの保護についてのみ 説明してきました。 ポインター認証付き。 それはもっと深い配列ですが、 あなたが目にすることは決してないでしょう。

    私たちはこの実装を設計しました 既存のコードと互換性を持たせるためです。 ですから、 皆さんもご自身のアプリケーションにぜひ 導入したいとお考えだと思います。

    それでは、そのために 必要な手順をご説明しましょう。

    さて、ご自身のアプリケーションで 採用を開始する前に。 埋め込むすべてのライブラリがまたは、 ポインター認証をサポートするリンク。

    もしあなたがこれらのライブラリの 作成者であれば、 その作業はあなた自身で行うことになります。 しかし、外部で開発された ライブラリを使用している場合は、 取引先に連絡を取る必要があります ポインター認証を採用させる そして、汎用バイナリを提供します。

    それが完了したら、ご自身のアプリケーションで 導入作業を開始できます。

    それを行うには、「拡張セキュリティを 有効にする」オプションを選択します。 Xcodeプロジェクトのビルド設定で 設定してください。 これにより、メモリ整合性の強制と ポインタ認証が可能になります。 そして、これをすると、 Xcode がプロジェクトを 自動的に構成します おなじみのarm64スライスを含む ユニバーサルバイナリを構築する ハードウェアで使用される 追加の ARM 64 スライス ポインタ認証をサポートする。

    一度に一つのことだけを取り 入れることに集中したいなら、 ポインタ認証のみに焦点を当てるには、代わりに 「ポインター認証を有効にする」 オプションを使用してください。

    ポインターをすべて再設計しました。 ポインタ認証に基づく保護はすべて、 既存のコードでは、 そしてほとんどのアプリケーションは 構築されますそして、 これらの保護機能がすべて備わった 状態で正しく動作します。 しかしもちろん、それは保証ではありません。 次のステップは、アプリケーションを 徹底的にテストすることです。

    さて、最初に遭遇するバグのいくつかは、 認証エラーによって検出されるようになった、 コード内の既存のバグ。 これは予想通りの結果だ。 これでこれらのバグがわかったので、 修正できるようになります。

    しかし、書かれた コードを持っている可能性もある ポインタ認証と互換性のない方法で。

    そして、それらについては、 いくつかの変更を加える必要があります。

    これらの不適合の根本原因は 意図せず未定義の動作を引き起こした場合。

    これらの操作は重複することが多く、 悪用されるバグも重複する。 攻撃者による攻撃も、 同じ防御策によって阻止される。

    実際には、ほとんどのコードはこれらの 問題に遭遇しません。 しかし、最もよく使われる 情報源をいくつか簡単に説明しましょう。 これまでに発生した 互換性に関するバグについて。

    私たちが目にした最も 一般的なパターンは、安全でない memcpyなどの関数を使用して、 ポリモーフィックなオブジェクトをコピーする。

    memcpyや類似の関数を使うのが 安全でない理由については既に説明しました。 これをしているとき。 しかし、これらの電話を 直接かけることはないかもしれません。 これらの操作を実行するコードや コンテナ型が存在する可能性があります。 そして、まさにそこに、 こうした失敗の事例が見られるのです。 これらのエラーの修正方法は、 より高レベルの言語機能を採用することです。 データ構造、またはオブジェクトの コピー用のライブラリ関数を採用する そして初期化も、これらはあなたの言語に 組み込まれているからです。 彼らはあなたの所有物の種類を知っています。 そして彼らは正しい意味論を保証するために 必要なすべての作業を行うだろう 可能な限り効率的に。

    さらに稀な例としては、 関数ポインタの上位ビットに 余分なデータを格納する方法がある。 コードがこのような処理を行うと、 そのストレージによって署名が破損します。

    この問題を解決するには、 このデータを移動する必要があります。 ポインタの下位ビットへ、 あるいは、そのデータをポインタの外に 完全に移動させるだけでも良いでしょう。

    これらは私たちが目にした 最も一般的なパターンです ポインタ認証を採用した コードもありますが、まだ非常にまれです。 極めて大規模なコードベースの 場合でも同様です。

    しかし、アプリケーションでこれらの パターンを認識している場合は、 それらは、あなた自身の養子縁組活動の 一環として対処する必要があるでしょう。

    必要な変更を行った後テストの結果、 アプリケーションは期待どおりに 動作していることが確認されました。 あなたはそれをユーザーに展開するでしょう。

    そして、どのリリースにも言えることですが、 新たなクラッシュの報告が 寄せられる可能性もあります。 そして、これらが認証失敗かどうかを 知りたいのですね。

    この診断のお手伝いをします。 プログラムが終了すると、 生成されたクラッシュログには、 診断メッセージが含まれます。 認証エラーが原因である可能性があります。

    ただし、クラッシュログを自分で 取得している場合は、 障害発生アドレスの最上位ビットを 調べることができます 同様の診断結果を提供するため。

    衝突が迫っていることを知っているだけで 認証失敗だけでは十分ではありません。 それでは、認証失敗の例を見てみましょう。 そうすることで、それらがどのように 表示されるか、 そしてどのように修正できるかを確認できます。 ここに、認証エラーが発生した 非常にシンプルなプログラムがあります。

    Xcodeのデバッガーで エラーを検出した場合。 最初は他のクラッシュと同じように 見えるだろうが、

    しかし、認証失敗によって発生する トラップは常に上位ビットを設定します 障害発生アドレスにおいて。 そして、それがここにある光景です。 さて、設定されている存在の正確な部分に 焦点を当てないでください。 それはハードウェアの世代によって 異なる場合があるからです。

    そして、私たちの小さなテストプログラムでは、 この呼び出しの直後に障害が発生しています オブジェクトのコピー機能へ。 そして、私の既存のコードが データをコピーする際に、 無効なオブジェクトが生成される可能性がある。 それでは、その関数を見ていきましょう。

    これは何かがうまくいかないデモなので、 当然のことかもしれませんが、この関数は、 Memcpyを使用して ポリモーフィックオブジェクトをコピーします。 なぜなら、以前はこれでうまくいっていたから だ。 この例を見れば、コード内でこのようなことが 起こるかどうかは非常に明白ですが、 これは、特注または特殊なケースのコンテナ内でのみ 発生する可能性が高い。 そしてデータ構造。

    幸いなことに、コンパイラは既にこれらの 問題を見つけるのに役立っています。 これらの危険な作業に対して 早期に警告を発することで、 ポインタ認証が有効になっていない場合でも。

    コードベースがそれを許可している場合、 これらの警告をエラーとして 扱うように設定する必要があります。

    これで問題点が分かりましたね。 どのように解決するかを決める必要があります。 そして、あなたにはいくつかの 選択肢があります。 それでは、いくつか例を見ていきましょう。

    最も簡単な解決策は、型指定のない メモリアクセス関数の使用をやめることです。 それは、mem が標準ライブラリに コピーまたは移動したということです。 オブジェクトの移動、コピー、 初期化を行うための関数を提供します。

    これらの機能により、 必要な作業が確実に行われます。 オブジェクトが正しく 初期化されるようにするために、 そして、安全であればMemcpyのような 関数を使用するでしょう。

    しかし、すでにこれらの低レベル機能から 離れつつあることを考えると、 より高度な言語機能を直接採用することを 検討すべきです。

    例えば、これらのコピー操作の安全な 同等物は次のようになります。 配置新しいもののようなものを使用する。

    私たちがこれまで見てきた 中で最も難しいケースで、 あなたにとっても非常に難しいケースです Memcpyを使用している 場合は修正が必要です なぜなら、オブジェクトの動的な型を 維持しようとしているからです。

    この問題を解決するには、コードの構造を 再構築する必要があるかもしれません。 言語レベルの多相性のようなものを使う。 例えば、この例では、 コピーを仮想クローン方式に置き換えました。 あるいは、これらのコピーを実行するために、 型を考慮した手動ロジックを採用する。 つまり、タイプをチェックするという ことですね。 もちろん、これは非常に 基本的なデモプログラムです。 認証失敗がどのように表示されるかを お見せします そして、それを解決するためのアプローチ方法についても 説明します。 しかし、ほとんどすべての認証失敗 すべての言語において、 同じように固定されている。 低レベルの操作から脱却する必要があります 代わりに、使用している言語が 提供するサポートを使用してください。 そのランタイムとライブラリ。

    ポインタ認証がコードを保護する 方法についてたくさん話してきましたが、 そして、C++で書かれた例も見てきました。

    しかし、ポインタ認証を採用する 必要はないと考えるかもしれません。 すでに養子縁組しているから あるいは、Swiftのような安全な 言語を採用する過程にある。

    しかし、それだけでは コードを保護するには不十分です。

    その理由を理解するには、 攻撃者がどのように攻撃を仕掛けてくるのかを 見ていく必要があります。 コードをターゲットにする。

    基本的に、攻撃者がアプリケーションを 制御するには、2つのものが必要です。 まず、彼らはあなたのアプリケーションの 状態を破壊するために 利用できるバグを見つける必要があります。

    この例では、安全でない scanf 関数の使用により、攻撃者は 結果バッファをオーバーフローさせる。

    第二に、彼らはその破損した状態の結果に 基づいて動作するコードを必要としている。

    ここでは バッファオーバーフローを利用できます エラー処理関数の内容を上書きする 呼び出し元の関数内で エラーハンドラを呼び出す場合。

    そのエラーハンドラが 呼び出されると、攻撃者が 選択した命令を実行します。 彼らはあなたのアプリケーションの 制御フローを引き継ぎました そして、彼らは望むあらゆる コードを実行できる。

    ソフトウェアの悪用について考えるとき、 元のバグだけでなく、 もっと多くのことを考える必要があります。 攻撃者がそのバグを使って何をしようとしている のかを考える必要があります。 それでは、その発信者について 今すぐ見ていきましょう。 それは、これまで何度も目にしてきたような、 安全でないC言語または C+ + 言語のコードです。 では、安全な言語で 表現するとどうなるのでしょうか? ええと、この関数をSwiftで書き直しました そして、C言語版とほぼ同じです。 実際、エラーハンドラを上書きするために 使用されたのと全く同じエクスプロイトが C言語の関数は、Swift版でも 置き換えることができます。

    繰り返しますが、 皆さんが理解しやすいように非常に 簡単な例を使用しています。 しかし、どの言語を使っても結果は同じです。 元のバグが何であれ、そして、 それがどれほど複雑に悪用されようとも。 それは、ユーザーが アプリを実行しているときに、 彼らは単にあなたのコードを実行している だけではありません。 彼らはすべてのライブラリから コードを実行しています あなたのコードと並行して実行されているもの。 つまり、どの言語を使っていても、 コードは存在する可能性のある バグから保護する必要があります プロセス内で実行されている 安全でないコードのいずれか。

    ポインタ認証を採用すれば、 それが実現できます。 攻撃者があなたのアプリケーションを侵害することが、 はるかに難しくなりました。 たとえそれを成し遂げたとしても メモリの整合性や強制などの 他の保護を回避するため。

    しかも、既存のコードにほとんど、 あるいは全く変更を加えることなく、 この保護機能を実現できます。

    これがポインター認証の使い方です。 攻撃者によるアプリの乗っ取りを防ぐため。

    それでは、エンリコ、フィリッポ、 そして私自身は、記憶、整合性、 執行、ポインタ認証は ハードウェアによってユーザーを保護し、 コンパイラ、オペレーティングシステム、 そしてアプリケーションがすべて 連携して動作します。

    きっとあなたは、これらのツールを使った作業は 実用的で、ほとんど、 あるいは全く必要ありません。 コードの変更、そしてそれは整合性に 大きなメリットをもたらしますそして、 アプリ全体の安全性。

    ありがとうございました。それでは、 カートの話に戻りましょう。

    オリバー、フィリッポ、エンリコ、ありがとう。 本当に素晴らしいものだった。 開発者センターの皆さん、次にご紹介するのは 休憩エリアに昼食場所を確保しました。 太平洋時間午後1時45分に、 またこちらで素晴らしい講演を3つ お届けしますので、ぜひご参加ください。

    ランチを楽しんでいただけたでしょうか。 オンラインでご覧になった方も、 楽しんでいただけたでしょうか。 朝食、昼食、夕食、あるいはちょっとした お茶をお楽しみいただけたなら幸いです。 適切なものであれば何でも。

    午後の講演を始める前に、 エンジニアリングチームはまだオンラインで 質問を受け付けています。

    午後のプログラムが始まります いくつかプログラミング言語を 紹介したいと思います。 C言語と C+ + 言語における 境界安全性の導入に関する実践的なガイド。 フクロウを歓迎しましょう。

    ありがとうございます。ありがとうございます。

    こんにちは。セキュリティツールチームの 者です。同僚のルイスも同席します。 今日のセッションは、拘束の安全についてです。 メモリ安全性のクラス全体を排除する技術 あなたのCおよび C+ + コードに存在する脆弱性。

    このセッションの内容は以下のとおりです。 まず、実際の脆弱性を動機として、 なぜ絆の安全性が重要なのかを説明します。

    では、その仕組みとは? 債券の安全性を確保すべき理由とは?

    そして、それを実際にどのように導入するか。

    また、より広範な債券安全なエコシステムを 構築するための取り組みについても話します。

    最後に、 C+ + でのアプローチについて 説明します。

    実際の例を挙げましょう。 最近、広く利用されている オーディオライブラリが、 ゼロクリック脆弱性の被害に遭った。 ゼロクリックとは、攻撃者が 任意のプログラムをサイレントに 実行できることを意味します。 ユーザーが何も操作しなくても コードが実行される。 ほとんどのプラットフォームにおいて、 これにより攻撃者はデバイスを密かに 乗っ取ることができる。 しかし、 Appleプラットフォームでは、 エクスプロイトは単に 失敗するだけですなぜなら、 ボンドセーフティ技術がこの種の バグ全体を生み出したからです。 悪用可能。そして今日、 そうすれば、まさにその防御機構をアプリに 組み込むためのツールが手に入ります。

    メモリの安全性は依然として 最大のセキュリティ課題である。 システムプログラミングにおいて。 あなたはおそらくすでに一生懸命探している でしょう 静的解析、サニタイザー、 コードレビューを用いてバグを修正する。 しかし、問題は攻撃者が 次々と新しいバグを見つけ出すことだ。

    バグ発見ツールは貴重です。 しかし、それだけでは攻撃者のモデルを 根本的に変えるには不十分だ。 脆弱性のクラス全体を排除する必要があるため、 バグが存在する場合、 それを悪用することはできない。

    メモリ安全性の完全な解決策は Swiftのようなメモリ安全な 言語を使用するには、 そしてそれは、新しいコードにとってまさに 正しい選択です。

    しかし、既存のコードベースとなると話は別だ。 時には数億行の CC+ + の完全な書き直しには 数十年かかるだろう、しかし、

    人々は今すぐに保護を必要としている。

    現実的な前進の道筋。 既存のコードは不可欠です。

    必要なのは、脆弱性のクラス全体を 排除する技術です。 個々のバグを見つけるだけではない。

    これらの技術は、完全な書き換えよりも 導入しやすいものでなければならない。

    そして重要なのは、段階的に 適応できる能力が必要だということだ。 だから、待つことなく今日から コードの保護を開始できます。 大規模な移住プロジェクトのために。

    本日、マークは5つの異なるメモリ安全性に 関するバグの分類。 これらはすべて重要な問題だが、 それぞれ異なる解決策が必要だ。

    そしてこの講演では バランスの安全性に焦点を当てます。 これは、生涯安全性の問題と並んで、 2大問題の一つです。

    先ほど触れた、安全性の問題に 関するオーディオコーデックの 脆弱性を覚えていますか? そして、これはメモリの安全性に 関する問題全体の約半分を占めている。

    それはつまり、バランスの問題に取り 組むということだ。安全性の問題により、 メモリの安全性の問題の半分が 解消されるだろう。そして、Appleの SI向けの安全技術を発見しました。

    アプリに画像フィルター機能を追加しようとしている と想像してみてください。

    バッファ、サイズ、そして ピクセルをループ処理する処理が必要です。

    しかし、ここでのループ条件に 注目してください。 使用するサイズは以下です。 最後の反復で1つのエラーが 発生するという古典的な問題を紹介します。 バッファの末尾から1つ 先の要素を書き込みます。

    これは簡略化された例ですが、 これは、まさに境界外エラーの 種類を表しています。 攻撃者の制御入力と組み合わせると、 数え切れないほどの現実世界の 悪用行為の根本原因となる。

    バウンスセーフティエクステンションの仕組みは 次のとおりです。 C言語では、バウンスセーフティによってこの 問題を解決します。 インデックス作成には、バウンス情報が 必要です。 コンパイラは、ポインタの バウンスを知らない限り、 ポインタへのインデックスアクセスを 許可しません。

    エラーメッセージを確認してください。 コンパイラは、その画像には バウンス情報がないと伝えています。 そのため、ゼロ以外のインデックスを使用して アクセスすることはできません。

    このエラーメッセージは、 必要なバウンス注釈の場所を示しています。 画像が指す要素の数をコンパイラに伝える。

    そこで、サイズで 数えるという概念が登場します。 このポインタがサイズ要素を指している ことをコンパイラに伝えます。

    これでコンパイラは 境界値を把握できるようになった。 メモリへのアクセス前に、 自動的に境界チェックを挿入します。

    境界安全バグがプログラムトラップを トリガーした場合 範囲外に書き込む前に。

    バグはコード内にまだ存在しているが、 もはや悪用することはできない。

    C言語プログラムはポインタをさまざまな 方法で使用します。 したがって、境界安全拡張機能は 一連の境界を提供する。 注釈。一般的なポインターパターンとそれぞれの ケースにどの注釈を使用するか。

    まずは、単一の要素へのポインタから 始めましょう。

    C および C+ + における バウンドセーフティ ボックスを調査する場合。 明確なパターンが見られる。 ほとんどの問題は、配列のインデックス付けと ポインタ演算に起因します。

    この図には、4つの整数から なる配列が示されています。 緑色の枠は、インデックス0から 3までの有効な要素を示しています。 赤い枠で囲まれた部分は立ち入り禁止区域です。 メモリ。 ゼロ点配列へのポインタを取得する 最初の要素において。そしてそれは安全です。

    しかし、配列インデックスやポインタ演算では、 配列の範囲を超えて、 その赤い領域にアクセスするのは簡単です。

    興味深いことに、C言語の ポインタのほとんどは、 実際にはポインタ演算を必要としません。 それらは、このメッセージ t のような単一の オブジェクトを指し示すだけです。

    それをインクリメントしたり、 配列のようにインデックス付けしたりすると、 範囲外になります。 危険であり、不必要である。

    必要なのは逆参照です。

    矢印を使用してメンバーにアクセスする または、スター演算子を使用して 直接逆参照します。

    そして、まさにその点を単一の注釈が 捉えているのです。

    このポインタは正確に 1つの要素を指しているか、 またはsingleの場合は nullであることを示しています。 コンパイラはポインタ演算と配列インデックス操作を 防止します。 ポインターをその単一のオブジェクトを超えて 誤って移動させることはできません

    これらのバグはコンパイル時に 検出されたためです。 デフォルトでは安全です。

    なるほど、ほとんどのポインターには シングルで十分ですね。 単一のオブジェクトを指すもの。 しかし、実際にインデックス付けが 必要な複数の要素へのポインタの場合 ポインタ演算を行うには、 バウンス情報が必要です。 安全にアクセスできる 要素の数を把握する必要があります。 有効な範囲はどれくらいですか?

    そのバウンス情報はどこかから 入手しなければならない。 幸いなことに、ほとんどのコードには 既にそれが備わっている。

    プロセスイメージについて考えてみましょう。 ポインタはサイズと並んで渡されます。

    またはメッセージTを考えてみましょう。 データポインタはデータサイズのすぐ 隣にあります。

    このパターンは、ポインタを用いた C言語関数のパスサイズに 関するあらゆる箇所に見られます。

    衝撃を受けた。それらを 並べて保管してください。

    情報は既に存在している。 それを明確に表現する方法が必要なだけだ。

    そこで「数える」が登場する これによって、これらのポインタの境界が 決定されていると宣言できます。 この別の変数によって。 あなたはそれを明確にしている。 カウント対象のコードに既に存在していたのは、 最も一般的な注釈です。 しかし、異なる境界パターンを捉える 他のものも存在する。

    少し修正した例で、別の例をお見せしましょう。 関数が今度はvoidポインタを受け 取ると想像してみてください。 不透明なシリアル化データを処理する。 利用可能なバイト数が不明なため、 型は特定できません。

    構造体でも同じです。 Imagineは、シリアル化されたデータ、 つまりvoidポインタを受け取ります。 構造は不明だが、データサイズはそれが 何バイト含まれているかを示している。

    ここで、注釈によるサイズ指定を使用します。

    要素数をカウントするのではなく、 バイト数をカウントします。

    では、別の例を見てみましょう。 allocate pixels関数は、画像を ピクセルの配列として割り当てます。 n 個のピクセル要素へのポインタを返します。 割り当てに失敗した場合はnullを返します。

    n個の要素を使用してカウントします nがゼロでない限り、 戻り値の型は間違っています。 null を返すと、 ポインタは n 個の要素を指しません。 それは何の手がかりにもならない。

    ここで「counted by」 または「no」を使用します。 これはN個の要素を指しているか、 そうでないかのどちらかを示しています。 ポインタがnullになる可能性がある一方で、 カウントがゼロでない場合は、 この注釈を使用してください。

    最も一般的なものについて説明しました。 しかし、サイズ5のような他の親向けの 注釈がもっとありますまたは、 null と Devi およびその他。

    完全なリストは、バインドセーフティ拡張機能に 関するドキュメントに記載されています。

    これで、バウンドセーフティエクステンションの 仕組みが分かりましたね。 そして、あなたがそれを採用すべき 理由は以下の通りです。

    安全性がしっかり保証されていることと、 導入が実用的であることの 2つの理由があります。

    まず、強力な安全性の保証は、コンパイラが常に 必要な残高チェックを挿入します。

    長年にわたり、開発者は Unisonや Fortify Sourceのような、 機会主義的な残高チェックツールについて。

    これらはそうです。これらのツールは貴重です。 しかし、彼らは最善を尽くして バグを捕まえている。 それはまるで、終わりのない モグラ叩きゲームを延々と続けるようなものだ。 見落としていた点を見つけ出してください。

    跳ね返り時の安全性は、 ゲームの流れを完全に変えます。 確実にチェックしてもらえます。 コンパイラはあなたの安全網として機能します。 バウンス情報が常に存在し、 常に正確であることを保証する。 これにより、この脆弱性クラスは 構造的に排除されます。

    まず、コンパイラはバウンス情報が 常に利用可能であることを保証します。 そのため、バウンスなしで ポインタをインデックスしようとすると、 コンパイラエラーが発生します。

    最初の関数において。 画像にはバウンス表記はありません。

    そのため、コンパイラは 配列へのアクセスを拒否します。

    in。 によってカウントされる2番目の関数は、 バウンスを提供します。 つまり、コードはコンパイルされ、 コンパイラはバウンスチェックを挿入する。

    これは、コードがコンパイルされる場合、 境界がチェックされることを意味します。

    そうですね。これは私のお気に 入りの機能の一つです。 バッファを更新したのに、サイズの更新を 忘れてしまったことは何度ありますか? この拡張機能により、 コンパイラは実際にその関係性を理解する ポインタとサイズ変数の間に、 コンパイル時に実行時に強制し、 つまり、意図せず境界を越えることはできないという ことです。 正確さ。

    冒頭の例を見てください。 データポインタは、下記のデータサイズに 関連付けられています。 この関数はデータ用のメモリを割り当てるが、 データサイズの更新を忘れている。 この典型的な間違いは、 通常、古いサイズ値を残してしまう。 範囲外エラーへ。

    しかし今ではコンパイラがそれを即座に検知し、 コンパイルを拒否します。

    修正するには、ポインターのサイズを一緒に 更新するだけで済みます。

    コンパイル時のチェックを超えて。 コンパイラは実行時チェックも挿入する。

    サイズフィールドが100に ハードコーディングされているため、 コンパイラは、100 が実際に 収まることを自動的に保証します 当初の割り当て分。

    これらの安全保証があるため、 拘束安全拡張を採用することは実用的である。

    まず第一に、ほとんどのポインターには 注釈は必要ありません。 スマートデフォルトは一般的な ケースを自動的に処理します。

    また、Abi互換性を維持しながら、 これを段階的に調整することも可能です。 互換性を損なうことなく、 一度に1つのファイルを変換できます。 残りのコードベースと連携して。

    まずは、スマートなデフォルト設定から 始めましょう。 メッセージ処理の例に戻ると、 この関数は、単一のメッセージ t オブジェクトへのポインタを受け取ります。 そしてそれを表現するために 「single」が加えられた。

    さて、このパターンは非常に一般的であるため、 バインドセーフティ拡張機能により、シングルが デフォルトになります Abi境界におけるポインターについて。 関数パラメータ。構造体フィールド、 グローバル変数、およびネストされたポインタ。

    したがって、このパラメータに 注釈を付ける必要はありません。 デフォルトでは既にシングルになっています。

    何か違うことをしたい場合、 例えば数えたい場合などにだけ 注釈を付ける必要があります。

    さて、あなたはこう 思うかもしれません。「おい、 ローカルポインターすべてに注釈を 付ける必要があるのでしょうか? 私の何百万行ものコードの中で? 答えは絶対にノーです ローカル変数はAbi境界で 公開されないためです。 コンパイラは実に素晴らしいことをする。 舞台裏では、自動的にそれらを ワイドポインターに昇格させる。 完全なポインタ演算が可能になり、 自動実行時チェックも可能になります。 しかも、ローカルコードに 注釈を追加することなく、 これらすべての安全性を確保できます。 とにかくうまくいくんです。

    以下に例を示します。プロセスイメージ関数は ローカル変数を使用します。

    現在位置を追跡し、 配列の末尾をマークするため。 どちらも自動的にワイドポインターになります。 注釈は不要です。

    PTRをインクリメントすると、 コンパイラは境界値も一緒に引き継ぎます。

    逆参照するとき。 TRは、注釈を追加することなく、 すべての安全性を自動的に バウンスチェックします。

    そして、これを採用する最も 実用的な理由がここにあります。

    これは、現実世界での段階的な導入を 想定して設計されています。 大規模なSQLデータベースを 一夜にして書き換えるために 開発を一時停止するのは現実的ではない。

    これらの注釈はポインタを変更しないため アビ境界における代表者。 全面的な書き直しは不要です。 高度に保護された 重要なファイルを1つ取得して、 今日からボンドの安全性を有効化できます。 そして、それを既存の注釈なし プロジェクトに直接リンクさせます。

    注釈なしの API が実際に使用される シナリオには次のようなものがあります。 システムヘッダーはデフォルトで必須です。 これらのヘッダーからのポインタは 安全でないものとして扱われます。 バウンス情報はありません。 いいえ。不渡り小切手は受け付けません。 コンパイラはそれらを検証できません。

    しかし、これによりバウンスセーフな コードがコンパイルされるようになる。 また、古いライブラリとの 相互運用性も備えている。

    以下に例を示します。 ファイルハンドルを開くには、 apply open を呼び出し、 ファイルポインタを取得します。

    ファイルは注釈付き システムヘッダーから取得されるため、 コンパイラはそれを安全でない ポインタとして扱い、安全な変数に代入します。 f を保存、

    明示的な型変換が必要です。

    そのためには、単一マクロに対して 安全でない方法を使用してください。 基本ポインタ型と安全でない ポインタを受け取ります。 これは私がこれらの点を理解している ことを示しています。 これは単一のファイルオブジェクトを 指しており、その責任は私が負います。

    目標は、これらの危険な構造を時間をかけて 監査し、排除することです。 適切な注釈が上流に追加されるため。

    よし。理論の話はこれで十分だろう? さあ、ここからが楽しいところです。 プロジェクトに境界安全対策を適用する 具体的な方法を以下に示します。

    手順は以下のとおりです。 まず、ヘッダーに注釈を付けます。 それから、ファイルを一つずつ 確認していきましょう。 ファイルに対して境界安全性を有効にします。 適応させて、テストとデバッグを繰り返す。 すべてのファイルの処理が完了したら、 Xcodeでバウンドセーフティを グローバルに有効にします。

    各ステップを順を追って説明します。

    まず、API契約が定義されている ヘッダー内のバウンス注釈を調整します。

    まずはこの見出しから見ていきましょう。 Peter のチェックドット h を含めてください。 これにより、バウンスセーフティに 関する注釈とマクロが提供されます。

    それからピーターを使ってください。 アビか他のシングルをチェックしてください。 ヘッダーを曲げるとき。 このマクロは、消費者が Abi ポインタを単一のものとして 自動的に扱うことを保証します。 危険ではない。

    最後に、必要に応じてカウント数やその 他のバウンス注釈を追加します。

    これで完了です。このヘッダーは バウンスセーフになりました。 別のバウンスセーフコードがこの 関数を呼び出す場合、 コンパイラはコースサイトに バウンスチェックを挿入します。

    次に、ソースファイルを1つ選択します。 拡張機能を有効にしてください。

    そのためには、コンパイラフラグ 「f」を追加します。 機能を有効にするための構築フェーズで 安全性を確認しました あなたが採用したソースファイルについて。

    次にコンパイルを行い、 コンパイラの診断結果に従ってください。 コンパイラは、不足している、 または一致していない注釈を即座に検出します。

    プロセスイメージのバウンスセーフティを 有効にすると、 例2の診断結果が表示されます。

    最初の文は、関数定義が 注釈と一致しなければならないと述べている。 ヘッダー宣言内。

    2つ目は、パラメータ画像に バウンス注釈がないと言っている。 そのため、インデックスによる アクセスは許可されていません。

    パラメータに「サイズ別カウント」 を追加します。 両方の診断問題を修正します。

    それではテストを実行し、 実行時チェックをデバッグしてください。

    トラップに引っかかった場合、 コンパイラが誤ったアノテーションを 呼び出したことになります。 あるいは、たった一つのエラーによって生じる、 このような実際のバグ。

    Xcodeは即座に実行を停止し、 何が起こったのかを正確に教えてくれます。

    参照範囲が上限を超えています。

    ここのロジックを修正すれば、 コードは正常に動作するようになる。

    試験に合格したら。 そのファイルは保護されています。

    残りのファイルは、時間をかけて 順次採用していくことができます。

    プロジェクト全体が準備できたら、 Xcodeのビルド設定で Bounce Safety拡張機能を 有効にしてください。

    そのためには、プロジェクトの ビルド設定に移動してください。 そして、セキュリティセクションの 設定を見つけます。 C言語のバウンスセーフティのための 言語拡張機能を有効にするはい。 それ以降、ターゲット内のすべてのCコードは 保護されており、新しいコードは 安全規則に従う必要があります。

    ここで明確にしておきたいのは、 これは単なる研究プロジェクトではないという ことです。 これは大規模な実証済みである。

    Appleは既にこの技術を用いて、 数百万行に及ぶ本番環境の コードを保護している。 それは、Appleプラットフォームを支えるカーネルの ネットワークスタックの中にあります。 オーディオおよび画像コーデック、セキュアブートライブラリが 組み込まれています。 N1ネットワークチップのファームウェアなど。

    現在、高度なセキュリティと機密性を備えた システムで顧客へ出荷されています。

    Appleは、毎日何十億ものユーザーを 保護するために、この仕組みに頼っている。

    さあ、今度はあなたの番です。これを活用して、 ユーザーの安全を守ってください。

    もちろん、C言語を書くなら、 パフォーマンスは重要だ。 きっとあなたは、何か裏があるんじゃない かと疑問に思っているでしょう。 そのため、カーネルのネットワーク全体で パフォーマンスが測定されました。 あらゆるマイクロ秒が重要となるスタック。 そして明確にしておきたいのは、このテスト中、 ダウンセーフティ機能は、すべての制御経路において 完全に作動していました。

    境界安全装置が有効になっている場合、 テストの 93% は、オーバーヘッドが 完全に範囲内に収まることを示しています 測定ノイズの許容範囲。

    実際に差が測定可能なごくわずかな 箇所においても、 その差は2%未満にとどまっている。 要するに、あなたは バウンドセーフティの究極の目標を手に 入れようとしているのです。 非常に実用的な性能を備えている。

    境界安全性はコードベースにとって 大きなメリットです。 しかし、それがどこでも 利用できるようになれば、 まさに状況を一変させるものとなる。 私たちはこのようにして、国境を越えた 安全なエコシステムを構築しています。

    目標は単純で、あらゆるプラットフォームで ユーザーを保護できるようにすることです。 それを実現するためには、リンゴだけではなく、 バウンスセーフティは、 clangのSwiftフォークで 既にオープンソース化されています。

    また、誰もが利用できるように、 LLVMのメインラインに 積極的に組み込まれています。

    しかし、事態はさらに深刻だ。

    AppleはC標準委員会と直接協力している。 債券の安全性をC言語自体に標準化する。

    最終的には、これはすべてのC言語デベロッパに 安全性をもたらすでしょう。 彼らがどのプラットフォーム向けに 開発しているかは関係ありません。

    それでは、 C+ + のアプローチについて ルイに話してもらいましょう。

    ありがとう。 みなさんこんにちは、私の名前はルイスです そして私はここAppleで C+ + 標準ライブラリの開発に携わっています。 ここに来られて嬉しいです。 それでは、 C+ + の側面について 詳しく見ていきましょう。

    C+ + はCとは異なるすでに 十分な情報を持つ多くの抽象化を提供している 安全性を確保するため。 例えば、標準スパンには ポインタとサイズが含まれているため、 どの境界が有効かがわかります。 アクセスされたとき。

    規格の他の多くの構成要素についても 同様である。 標準ベクトル、標準文字列、 標準配列などのライブラリ。

    しかし、 C+ + 標準ではこれらの API の安全性を強制することは 要求されていません。 そして実際、 C+ + の標準ライブラリはこれまで そのようなことをしてこなかった。

    例えば、コード右側は、 C言語のプロセスを C+ + に直接翻訳したものです。 ULが先に紹介した画像関数。

    生ポインタではなく、標準の スパンを使用します。 しかし、標準スパンを使用している にもかかわらず、 このコードはデフォルトでは 境界安全性を強制しません。

    Xcode、 それを 変更できるようになりました。

    これは、 C+ + のセーブバッファと呼ばれる 2つのアプローチを用いて実現されます。 まず、 Xcodeはツールを提供します C+ + コードが慣用的な方法を使用している ことを確認するのに役立ちます バッファにアクセスする際に 標準ライブラリが提供する抽象化。

    第二に、強化された C+ + 標準ライブラリを有効化できます 多くのAPIにおける 不正使用を検出するため。

    さて、コード内でより安全な抽象化を 採用できるようにするために、 Xcode は、場所を特定できる 診断機能を提供するようになりました コード内で、バッファへのアクセス方法が 慣用的でない箇所があります。 例えば、このコードは プロセスイメージのバージョンです 生ポインタを使用して記述された関数。 この場合、新しいXcode診断機能はこの コードにフラグを立てるでしょう。 生ポインタを使用してインデックスを 作成するため、安全ではないからです。

    これにより、場所を特定できます バッファにアクセスするための慣用的な 構文を使用していないコード そして、その問題を解決するため。

    この場合、一つのアプローチは 標準のspanを使ってコードを書き直せば、 エラーは解消されるでしょう。

    さて、慣用的な抽象化を使用する コードを実際に安全にするために、 Xcodeは、強化された C+ + 標準ライブラリも提供しています。

    Xcodeの設定で有効にすると、 標準ライブラリは、既に 含まれていた既存の残高情報を使用します。 特定のAPIの使用状況を確認するため。

    この例では、標準スパンに インデックスを付けています。 強化機能が有効になっている場合、 既に持っている既存の境界情報を使用します。 アクセスが有効であることを確認するため。

    さて、インデックスが有効でない場合、 堅牢な標準ライブラリは、 プログラムが確実に終了することを保証します。 これは、実行を継続して 破損させることができないことを意味します。 さもなければ、アプリが 危険にさらされるでしょう。

    また、APIの使用方法や契約内容に 変更がないことも特筆すべき点です。

    強化された標準ライブラリも、 結局はISO規格に準拠した C+ + ライブラリに過ぎない。

    強化ライブラリが有効になっている場合でも、 ABIは変更されません。 つまり、コードの変更は一切不要です。 安全性の向上というメリットを享受するため。 これにより、今すぐにでも セキュリティ強化策を導入しやすくなります。

    新しいXcode診断機能と標準ライブラリの 強化機能の両方を有効にするため。 セキュリティ設定の下にある ビルド設定に移動してください。 また、 C+ + で境界安全なバッファの 使用を強制できるようにします。

    場合によっては、安全でない 構造を使用する既存のコードが 存在する可能性があります。 しかし、まだ現代的な言い 回しを使うように更新することはできません。

    強化された標準ライブラリを引き続き活用する コードに新たなエラーを発生させることなく、 すぐに修正できます。 強化された標準ライブラリのみを有効にするには、 以下にアクセスしてください。 Apple Clang言語C++のビルド設定 さらに、 C+ + 標準ライブラリのセキュリティ強化を 有効にすることを選択します。

    これは単なるデバッグ機能ではないという 点も重要ですよね? デバッグ機能は生産性を向上させるのに 非常に役立ちます。 しかし、それだけではコードを実行時に 真に安全にするには不十分です。 本番環境のデバイス上で実行されています。 実際、強化された標準ライブラリを使用する コードは出荷されることを想定しています 生産および 硬化標準ライブラリの機能は、 その価値を最大限に引き 出すために非常に慎重に設計されています。

    これにより、本番環境で コードをより安全にすることができます。 ユーザーのデバイス上で実行され、 実際のデータを扱う場合、 だからこそ、安全性が真に重要になるのです。

    強化された標準ライブラリを使用する場合、 多くのAPIは追加の安全性を提供します。 さて、一般的なメンタルモデルは、コンテナが APIにアクセスするというものです。 コンテナの変更APIは 直接サイズを取得できます 要求事項が厳格化された。 実際、それらのAPIには既に 必要な情報が含まれています。 境界を確認するために、 そして、これらのAPIの 不正使用を検出することは、 直接的なセキュリティ上の価値を提供する。

    例えば、コンテナのインデックス演算子など。 彼らは元のやり方に戻った。 それらはすべて硬化している。

    オプション値へのアクセスも強化されています。

    一般的に、チェック済みの前提条件はどれでも 信頼できます。 ISO C+ + 26に準拠した 強化実装において、チェックを行う。

    標準ライブラリが既に デフォルトでチェック機能が 提供されています。 例えば、標準関数を呼び出す場合 関数が空の場合、既に例外が発生します。 強化はこれらのAPIには影響しません。

    他にも簡単に強化できるAPI、 しかし、それは限られたセキュリティ価値しか 提供せず、強化もされていません。

    アプリのセキュリティ強化によるパフォーマンスへの 影響を最小限に抑えるために、 実際にセキュリティ上の価値を提供する チェックが優先されます。

    例えば、ヌルポインタから 文字列を構築することは技術的には 正しくない。しかし実際には、 これは既にセグメンテーション違反を 引き起こし、 プログラムを終了させて​​しまう。 そのため、明示的なチェックを追加することによる セキュリティ上のメリットは限られている。 その場合は。

    最後に、ハードニングの例外として 注目すべきなのがイテレータです。 イテレータは一般的に十分な情報を格納しません 境界チェックを実行する。 その情報を追加するには、 Abi を変更する必要があります。 そうなると、養子縁組ははるかに 難しくなるだろう。 そのため、イテレータへのアクセスは 強化されていません。

    これで、どのAPIが 強化されているかを十分に理解できたので、 どのような体験が期待できるかについて お話しします。 堅牢なアプリケーションを開発する際。

    そのため、セキュリティ強化チェックが 失敗すると、 プログラムはXcode内で終了します。 強化の主張が失敗した場所に連れて行かれます。 これは標準ライブラリに含まれています。 そして、左側のスタックフレームセレクターを 使用してナビゲートできます。 あなた自身のコードへ。

    デバッグコンソールには、エラーメッセージが 表示されます。 失敗に関する追加情報。 そして、Xcodeで 通常のデバッグ ワークフローを使用して 理解することができます そして問題を解決する。

    配送アプリの場合は、少し事情が異なります。 アタッチするデバッガーがないため、

    プログラムはトラップによって終了します。 C+ + におけるC言語の境界安全拡張の 場合と同様です。 C言語の場合と同様に、 このメカニズムは最も速い そして、プログラムを終了させる 最も安全な方法は、 潜在的に悪意のある 攻撃者にとって選択肢が少ないため アサーションが失敗した後に、 プログラムの制御フローを迂回させる。

    具体的には、コンソールにメッセージが ログ記録されないことを意味します。 これにより、プログラムに 関する情報の漏洩を防ぎます。 また、バイナリのサイズをできるだけ 小さく保つことも保証します。 診断文字列を実行ファイルに保存しないことで、 可能な限りこれを実現します。

    しかし、それだけではない。 Xcodeはさらに追加のチェックモードも 提供しています。 これらはそれぞれ異なる 性能上のトレードオフを提供する。

    私がこれまで言及してきた強化モードとは 実際には高速モードと呼ばれています。 高速モードに加えて、 Xcodeには、コストのかから ないチェックを追加する 拡張モードも用意されています。 ただし、必ずしもセキュリティ上重要な 問題ではない。

    このモードは、厳密なプログラミングを 保証するのに最適です。 パフォーマンスコストが高すぎる。

    さらに、Xcodeは拡張モードに 加えてデバッグモードも提供しています。 デバッグモードでは、交換時にさらに 徹底的なチェックが行われます。 より大きなパフォーマンス効果を得るために。

    例えば、デバッグモードでは、 C+ + ライブラリは、コンパレータが 提供されるかどうかをチェックできます。 標準ソートは、ソートに 必要な特性を備えています。 これは、アプリ内の微妙な意味論的バグを 検出するのに非常に役立ちます。

    これで、高速モードと拡張モードを本番環境で 使用できるようになりました。 デバッグモードは開発時のみ使用すべきである。

    異なるファイル内で異なる モードを混在させることも可能です。 これは、コードベースに 段階的にセキュリティ強化を導入するために 使用できます。あるいは、 パフォーマンスをより細かく 調整する場合にも使用できます。 例えば、広範囲なまたは コードベース全体を高速に チェックする、ただし、 強化を無効にする パフォーマンスに非常に 敏感な単一のソースファイル内。

    そして、硬化処理は阿比に影響を与えないため、 これらすべてがシームレスに機能します。

    これらの機能が一般公開されることに、 本当にワクワクしています。 Xcodeでは、実際、 Appleはこの技術を開発してきました。 かなり前から、そしてそれを社内で採用して 今日に至るまで。

    特に、この技術はWebKit全体で 採用されました。 また、カーネルの一部を含む、 オペレーティングシステムの複数の 部分にも存在します。

    重大なパフォーマンスへの影響は観察されず、 複数のバグが発見された。 中には非常に捉えどころのないものもあった。

    Apple自身の経験に加えて、 この技術が業界全体で活用されている 事例は数多く報告されている。

    例えば、Googleは 自社のシステム全体への展開を文書化しました。 サーバー群。これは以下に対応します。 数百万行に及ぶ、パフォーマンスに 大きく影響するコード。

    微調整後、パフォーマンスへの影響はわずか 0.3% に抑えられた。そして、 セキュリティ上重大なバグを含む 1000件以上のバグを発見したと報告した。

    業界で採用されているもう 1つの例は C+ + 26です。 これは、高速モードに基づいた強化された 標準ライブラリという概念を採用した。

    全体的に見て、今回の経験は 非常に良いものでした。 そして、これがXcodeで一般公開されることを 本当に嬉しく思っています。

    さて、Xcodeが現在提供している ツールについて説明しました。 C言語とC++言語の両方において、 重要な脆弱性クラスを排除する お手伝いをします。 これは、拘束安全拡張を採用し 始めることができることを意味します。 ファイルごとにCコード内で実行します。 コードの中で最もセキュリティ上重要な 部分から始めるべきです。 そして準備ができたら 残りのコードに取り掛かってください ですから、 C+ + コードを含む プロジェクト全体で有効にしてください。 高速モードをすぐに有効にする コードの変更を必要とせずに、 アプリケーションの安全性を向上させる。

    テストおよび開発中は、 デバッグモードを有効にする必要があります。 これにより、通常見逃してしまうような 微妙なバグを発見し、 コード内でバッファにアクセスする際に、 標準ライブラリの慣用的な抽象化。 新しいXcode診断を有効にして、 あなたがこれから学ぶことについてもっと 知りたい場合は、 本日発表した内容については、 詳細な資料がオンラインで入手可能です。

    人々はあなたのコードの安全性に 依存していることを忘れないでください。 そして、すべてのステップが重要です。 さあ、今日から始めて、 これらの機能を試してみてください。 それでは、カートに返します。

    ありがとう、ルイ。 それでは、少し休憩しましょう。 太平洋時間午後8時55分に、本日の 最後の講演を再開します。 ありがとう。

    おかえり。 CとC++から離れて、 それでは、セキュリティに 関わるコードをSwiftで 書く方法についてお話してくれる Dougさんをお迎えしましょう。 ダグ。

    ありがとう。

    Swift言語チームのダグです。 今日は同僚のフェリックスと一緒に、 メモリ、安全性、そして Swiftについてお話しします。

    したがって、メモリの安全性は 重大なセキュリティ上の課題である。 さて。他のプレゼンテーションでは、 Cおよび C+ + コードベースにおけるメモリ安全性の バグを見つける、あるいは、 それらがセキュリティ上の問題となるのを防ぐ。 しかし、これらのどれも包括的なものではない あるいは単にメモリの安全性の問題を 定義するのと同じくらい効果的 プログラミング言語そのものの中に。 それではまず、 Swiftの設計がどのように メモリの安全性に関する問題に対処する。 次に、パフォーマンスについてお話しします。 そして、最近導入された Swiftの機能の使い方 低レベルコードから最高のパフォーマンスを 引き出すために 安全性を犠牲にする。

    さて、メモリ安全言語への移行は非常に 長い時間がかかる。 それでは、安全でないコードをカプセル化するための ベストプラクティスについて説明しましょう。 そして、C言語ファミリーからSwiftへ 段階的に移行する方法。

    まず第一に、メモリの安全性は 包括的な概念ではありません。 あらゆるエラーを防止することについて。 優れた言語設計は、いくつかの種類の エラーの処理方法を定義できる。 あるいは、コードにそれらを組み 込むのをより困難にする。 しかし現実には、プログラミングエラーは 起こり得る。 つまり、メモリの安全性とは、プログラムが 記述どおりに動作します。 それは一見するとばかげた話に聞こえる。 もちろん、プログラムは 書かれた通りに動作します。 しかし、先ほども話したように、 攻撃者がメモリの安全性のバグを悪用すると、 彼らは、コードに 書かれていないことをプログラムに 強制的に実行させることができる。 だからこそ、メモリの安全性は セキュリティにおいて非常に 重要な部分を占めるのです。 例えば、メモリ安全性のバグがどこかに 存在すると、 C言語や C+ + のコードを使えば、 プログラムにほぼ何でもさせることができます。

    メモリ安全性の高い言語は、 このような不条理な事態を防いでくれる。 これで、2つの方法で実行できます。 そのため、メモリを含む可能性のある コードのコンパイルを拒否することができます。 安全性の問題、または実行時に チェックを挿入して検出することができます 何かがうまくいかなかったとき。 これらの戦略を組み合わせると、 実際には、Swiftは コンパイル時とコンパイル時の 両方で異なる手法を組み 合わせて使用​​しています。 そして、後ほど説明する 実行時チェックについても触れておきます。 ここにはルールが一つしかない。 つまり、潜在的なメモリ安全性の 問題が発生した場合、 このプログラムは継続してはならない。 破損した状態で続行しようとすることは、 まさにプログラミングの エラーはメモリ安全性の脆弱性となる。

    これについては以前にも話しました。 そして私たちはしばしば 記憶の安全性を損ないます プログラミング言語が対処する 必要のある5つの異なる軸に分類する。 つまりこれらは安全装置であり、 寿命安全タイプ安全、初期化安全、 およびねじ安全。 C言語ファミリーは、これらの軸のいずれに 対しても安全性を提供しません。 ただし、それらのいくつかについては、 緩和策を講じることで対処できる。 では、Swiftがこれらの異なる 領域それぞれにどのように 対応しているのかを詳しく見ていきましょう。

    そして、安全面は最も簡単な問題だ。 これは、アクセスがメモリブロック内であることを 確認するためのチェックです。 そのメモリ領域外には アクセスしないでください。 C言語で見たように、 割り当てられたメモリ領域の末尾を超えて ポインタを調整することができます。 ブロックしてから、他の無関係な値を読み 取ったり変更したりします。 メモリの安全性に問題を引き起こす。

    このSwiftコードは、同じ 脆弱性を意図的に作り出そうとするものです。 12個の要素を持つ配列があります。 私たちは15番目の要素に アクセスしようと試みます。 Swiftは実行時に 境界チェックを行う予定です 同様のものを即座に捕らえるために 先ほどお話しした バウンドセーフティについてです。 これは簡単な方だ。 ここから先はもっと面白くなるぞ。 つまり、生涯の安全性がそれを保証するのです。 メモリにアクセスした時点で、 そのメモリは依然として有効です。 C言語では、ライフタイム安全性に 違反するコードを書くのはかなり簡単だ。 無料使用後の利用のようなもので、 コードが割り当てられたメモリの一部を解放する そして、この古いポインタを介して アクセスしようとします。 それは今では全く別のことを 指している可能性がある。

    Swiftは無料版を廃止することで、 無料版以降の使用をなくします。 つまり、ここに何らかのコードがあれば、 私のクラスのインスタンスを割り 当てることができます。 ローカル変数に格納してください。 それを使って、そのオブジェクトの メソッドを呼び出すことができます。 そして、どこにも無料のものはないという ことを覚えておいてください。 代わりに、コンパイラは破棄を挿入します そのインスタンスが使用されなくなった場合、 そしてコンパイラは常に 正しい方法でそれを行う、ということですよね?

    Swiftのコレクションクラスでも、 同様の自動的なライフサイクル管理が 用いられています。 これらは配列や辞書のようなものです。 ここで、最初の行で配列が作成されます。 使用されなくなると、自動的に 割り当てが解除されます。

    Swiftは自動参照カウントと呼ばれる 技術を使用しています。 そのため、私たちは他のより 伝統的なゴミ収集方法ではなく、 この方法を選択しました。 なぜなら、非常に優れた 工学的トレードオフを備えているからです。 自動参照カウントがある場合、 基本的にプログラミングできます メモリ管理を気にせずにSwiftで記述する。 すべてのパターンが機能しているようです。 そして、ほとんどの場合、 寿命のことを考慮していない。 一方、自動参照カウントもあります。 非常に高速です。オーバーヘッドが非常に低く、 パフォーマンスとメモリ使用量の両方において、 そして、あなたが目にするような間はありません より伝統的なゴミ収集方式を採用した。

    しかし、時には 実行時のオーバーヘッドが ゼロであることを保証する必要がある 場合生涯にわたる安全性を維持するために。 そのため、Swiftは コピー不可能な型も提供しています。 これらは、固有の所有資源に 対する所有権を表すものです。 ここにはトレードオフがある。 つまり、互換性のない型は、 より制約の多いプログラミングモデルを 持つということだ。 所有権についてもっと真剣に考える必要がある。 しかし、その代わりに オーバーヘッドはゼロになります。 非コピー型については、この講演の後半で 改めて取り上げます。

    型安全性とは、誤った型のメモリに 再度アクセスすることを防ぐ仕組みのことです。 C言語では、型安全性の問題を 簡単に作成できます。 いくつかの異なる方法で。 では、メモリ上のこのセルに 整数を書き込むとしましょう。 さて、後で組合員を通して処理するか、 あるいは明示的なキャストを 使用することもできます。 そしてそれをファイルとして読み 戻したため、型の混乱が生じた。

    Swift は、C の共用体と型キャストのこれらの 機能と同等の機能を提供します。 しかし、どちらも構造上、 安全性を考慮して設計されている。 Swiftの列挙型は差別的です。 差別的な組合、 つまり、現在どのオプションが 有効になっているかをエンコードしている ということだ。 ここにリソース列挙型があります。 ファイルを保存するか または、リソースにアクセスするための 整数識別子を保存することもできます。 switch文を使用して パターンマッチングを行います。 これにより、間違ったメンバーに アクセスすることは決してありません。 なぜなら、これらは これはペアアクセスです。

    スウィフトの型にはめられた役柄も同様で、 つまり、ここにあるSwiftコードは、 クラスと1つのサブクラスを定義しています。 そのサブクラスはメソッドをオーバーライドし、 独自の別のメソッドを導入します。 ごく典型的な オブジェクト指向プログラミングだ。 ここではダウンキャストを試してみましょう。 ここでの as 質問は、 指定されたオブジェクトを私のサブクラスに ダウンキャストします。 オプション値を生成します インスタンスを私のサブクラスとして含むか、 あるいは、ダウンキャストが 失敗した場合は空になります。 つまり、それがサブクラスの インスタンスであれば、 コードは本文内で実行されます。 そうであれば、安全な別の方法を呼び 出すことができます。 ダウンキャストが失敗した場合、 オプショナル型は空になります。 if文の本体は実行されません。 これにより、キャストによる 潜在的なメモリ安全性の脆弱性が排除されます。 また、型変換の誤りによるプログラミングエラーを 回避するのにも役立ちます。

    初期化の安全性も比較的直接的な例です。 つまり、これがメモリが再度初期化される前に 読み取られるのを防ぐ仕組みです。 C言語ではそれは必要ありません。 ローカル変数を構築できます そして、初期化される前に 直接使用すればよいのです。 Swiftで同じことをしようとすると、 Swiftコンパイラはこの試みを拒否します。 つまり、変数に値を代入または 初期化していないことが指摘されています。 そしてコンパイル時に拒否されます。 したがって、メモリの安全性に 関する問題は発生しないはずです。

    最後にして最も厄介なのは、 ねじ山の安全性です。 つまり、スレッドセーフティ違反とは、 どこかでデータ競合が 発生することを意味します。 プログラム内でメモリ安全性の問題を引き 起こす可能性があります。 そして、たとえあなたの言語は、 他のあらゆる側面において安全です。

    この例では、共有可能な 可変リソースがここにあります。

    関数 replace resource はそのリソースの値を変更します。 この識別子にその型を設定することも 含まれます。

    これが1つのスレッド内で 起こっていると想像してみてください。 さて、別のスレッドで、 リソースを使用する関数が切り替わっています 同じ共有リソース上で。 ここでデータ競争があったとしたら、 それは、あるスレッドがそれを ファイルとして認識している ことを意味する可能性がある。 同時に、別のスレッドが整数を上書きしている。 実際のファイルインスタンスを 整数で上書きします。 Swift 6 並行処理モデルは、 以下の方法でこれらのデータ競合を防ぎます。 共有された可変状態への同時アクセスがないことを 保証する。 さて、それに加えて、 Swiftは安全な取引方法を提供します データ競合を高レベルで 引き起こさない並行処理。 その一つが俳優だ。 つまり、アクターとは、 その状態をカプセル化するタイプのことである。 そして、同時変更から保護する。 ここでのリソース変数は、アクターの状態の 一部です。そのため、 Swift は リソースの使用を保証しますまた、 その状態に影響を与える 可能性のあるリソースの置き換えは、 決して同時に実行されません。

    これは、Swiftのasync/awaitモデルを 使用して 一貫して適用されます。したがって、 アクターのメソッド呼び出しは常に非同期です。 呼び出し元は、アクターが コードの実行を完了するまで 待たなければならない可能性があるためです。 その判断を下す前に、 別のスレッドで議論すべきです。

    Swiftは、データ競合の安全性を確保するための 低レベルのプリミティブも提供しています。 ここでのミューテックス型は、 アクセス可能なものを表します。 一度に一本ずつ糸を通すように。

    保存されたデータへのすべてのアクセス ミューテックス内では、この 幅ロック関数によって、 そのデータへの一時的なアクセス。 クロージャ内部では、 ミューテックスにより単一のスレッドのみが 実行できることが保証されます。 同時に閉鎖処理を実行する。

    つまり、迅速な記憶力と安全性が、 言語設計に組み込まれているということだ。 ここには、とても難しい利点があります 自分で体験するまでは、 それを伝えることはできない。 メモリ安全な言語を使用している場合、 それは単に心配しなくて 済むということではないのですか? 私はメモリ安全性の脆弱性を意図的に 作り出しているのでしょうか、 それとも脆弱性を探す必要があるのでしょうか? 完全にそのことを考えなくなるんです。 そうすれば、コードの正確性に 全神経を集中させることができます。 そして、メモリの安全性とは 関係のないその他の懸念事項。

    さて、もしあなたがC言語ファミリー出身なら、 おそらく、このメモリの安全性が 性能を犠牲にする。

    つまり、大まかに言えば、 Swiftはネイティブコンパイル言語です。 メモリ安全性モデルを効率的に 実装する機能を提供する。 そして多くのプログラムにとって、 それで十分だ。

    しかし、非常に低レベルのコードでは 安全性の低い C Swift 6 2のパフォーマンスに合わせるために導入された 役立つ安全な抽象化をいくつか紹介します。

    C言語で例を見てみましょう。 これはデコーダーです。 ランレングス符号化を使用する画像の場合。 つまり、ループ内では 入力バッファから一度に 4バイトずつ読み取っているということです。 これがカウントとピクセルデータです。 そして、その結果を出力バッファを 通して書き出すのです。 その過程で、境界チェックを手動で 行っていることがわかります。 このCコードには、実際には 当てはまらない多くの前提があります。 実際に検証済みです。 したがって、カウントパラメータは 対応するバッファのサイズを正しく記述する。 入力バッファと出力バッファが 何らかの奇妙な方法でエイリアシングしないことを 前提としています。 そして、他のスレッドによって 変更または解放されることはありません。 このプログラムが実行されている間。 以下は、同じコードをSwiftに 翻訳したものです。 つまり、入力バッファはデータとカウントの 両方をカプセル化した配列である。 だから、あなたは知ることができます。 そして、データが消えてしまうこともないことを 保証します。 または、マルチスレッドプログラムであっても、 この関数が実行中に 変更される可能性があります。

    配列へのアクセスは 境界チェックされるようになりました。 エラーが発生するとトラップされます 実行時にメモリ安全性の 脆弱性となるのではなく、 そうすることで脆弱性を回避できる。 でも、私はパフォーマンスについて 話すと言ったでしょう。 それでは、それについて見ていきましょう。 ループ内で適切な境界チェックを行うことで、 コンパイラは境界チェックを完全に 最適化によって削除できる場合が多い。 そうすることが安全だと証明された場合。

    Swiftのコピーオンライト配列は 参照カウントを使用するようになりました それらの実施において。 繰り返しになりますが、 コンパイラは多くの場合、 すべての参照カウントトラフィックを最適化して 取り除くことができます。 この例ではまさにその通りです。 しかし、この追加操作は配列に 新しい要素を追加することになります。 配列に十分な空き容量がない場合、より 多くのストレージを備えた新しいメモリを割り 当てる必要があるそして、 既存の要素をすべてそこにコピーします。 それは以前のC言語による 実装よりも遅くなるだろう。 それは単にポインターを通して ピクセルを書き出していただけだった。

    ここにはもう一つ問題があります。 つまり、この設計では クライアント自身が配列を持つことを 強制されるということです。 彼らに独自のコピーを提出するよう 要求することができる。 以下に例を示します。配列にデータがあります。 しかし、幅が単純なヘッダーで 構成されています実際の出力画像の高さ、 続いて、実際にデコードしたい 画像データが続きます。 さて、ここでの主な問題は、 このランレングスエンコードされた ピクセルデータのすべてをコピーするには、 これまで開発してきた デコード関数を呼び出すだけです。 デコードではピクセル配列全体を読み 込む必要があるため、 それは余分なヒープ割り 当てとすべての画像データのコピーです。 それは絶対に望んでいないことです。

    関連する問題があります。 つまり、デコード処理によって 結果配列が割り当てられるということです。 いつも山積みになっている。 この特定の画像デコード処理であれば、 それで問題ないかもしれません。 しかし、ピクセルを配置してほしいという 別の電話がかかってくるかもしれません。 ある特定の場所で、 おそらく、既に割り当てられている 固定サイズのフレームバッファに 格納されるでしょう。 そのためには、結果をもう 一度コピーする必要があるでしょう。 そのため、このような問題は 低レベルではよく発生する可能性があります。 非常にパフォーマンスに敏感なコードベース、 配列スライスや汎用コレクションを使用すれば 部分的に対処できます。 しかし、それらは扱いが難しい場合がある。

    そこで、新しいspan型の ファミリーが登場するのです。 つまり、スパンは連続したメモリへの安全で 低オーバーヘッドのアクセスを提供する。 Swiftで安全でない バッファポインタ型を使用したことがある場合、 スパンは、それらに対する 安全な対応物と考えることができます。

    スパンの背後にある重要な考え方は、 それが連続した範囲を参照するという ことである。 所有していないメモリ。 ポインタに長さを加えたものと考えてください。 なぜなら、それがまさに メモリ上で表現される方法だからです。 spanは完全なメモリ安全性を提供します。 コンパイラによってチェックされる方法で、 生涯にわたる安全性を提供します。 実行時のオーバーヘッドは一切ありません。 すべてのアクセスに対して境界チェックを 行うことで、境界安全性を確保します。 しかし最も重要なのは、参照する ストレージを所有していないということです。 その代わりに、ストレージを所有する 様々なタイプのシステムと相互運用する。 コピーオンライト配列への参照を持つ スパンを取得できます または、固定長のインライン配列。 また、安全でない ポインタ型とも相互運用します。 これは、安全でない言語とやり 取りする際に重要です。または、 spans より以前に作成されたコード。

    span 型のファミリーは Swift 6.2 で導入されました。しかし、 スパンは非常に重要だと考えているため、 これらのタイプをバックデプロイしました Appleのオペレーティングシステムのかなり 古いバージョンまで。 そうすれば、今すぐ養子にすることができます 展開目標を引き上げる。

    さて、ランレングスデコーダへの入力として spanを採用する時が来ました。

    それほど手間はかからなかった。 パラメータの型を配列からスパンに 変更しました。これは、spanが 同じAPIを提供しているため機能します。 配列が行うように要素に アクセスするためのものです。 そしてこのコードは データを読み込んでいるだけなので、 それはそれを変更しようとしている わけではありません。 コピーが返ってきません。 この機能に関しては、 他に何も変更する必要はありませんでした。 さて、何が変わったかというと、 API契約呼び出し者が今必要としているものは 配列の代わりにスパンを提供する。 それでは、呼び出し元のコードに戻って、 その方法を見ていきましょう。

    まず最初に、すべての配列にはスパンを 生成するspanプロパティがあります。 このようにすれば、コードを コンパイルできるようになります。 最後にspanタグを追加するだけです。 それは確かに効果があります。しかし、 パフォーマンスの向上にはつながりません。 まだこの新しい配列を作成中なので、 スパンを取り込む前に、 すべてのデータをコピーします。 私たちはもっとうまくできるはずです。 だから代わりに、 これから行うのは、元の配列から スパンを取得することです。 そして、私たちが関心のある 部分だけを渡すデコード機能へ。 読み取りコードは、それに 関連するスパンのみを受け取ります。 しかし、追加の割り当てもコピーもありません その間もメモリの安全性は維持される。

    この例を見ると、span は 単なる置き換えのように見えます。 配列の場合、そうではありません。 つまり、それは他のユーザーが 所有するストレージへの参照です。 そこで、実行時のオーバーヘッドなしにこれを 安全にするために、 スパン型自体には、いくつかの 必要な制約があります。

    つまり、スパンは非脱出型と呼ばれるものです。 これは、上記に示したチルダで エスケープ可能な構文で記述されています。 この構文をそのまま使用できます span と同様の動作をする、 独自の非エスケープ型を定義する。 今や避けられないタイプで、 先ほど行ったように、 関数への引数として渡すこともできます。

    ただし、関数から スパンを返すことはできません。 非エスケープ型の値を返すことができるのは、 その寿命は、パラメータの 1つに結びついている。

    これが何を意味するのかを知るために、 最初の実行関数の本体を 詳しく見ていきましょう。 つまり、このコードは最初の要素に 一致する要素の連続を見つけています。 そして、内部のループは 最初の不一致が見つかった時点で抜け出す。 ここで重要なのはその論理ではなく、 最終的な結果です。

    さて、ここで私たちは 何を返せばいいのでしょうか? 取得したデータパラメータから 直接抽出したスパンを返します。 それは、その中の関連部分だけです。 そしてそれは問題ありません。 それは、私たちに情報を提供してくれた発信者が そのスパンによって、結果として 生じるスパンが十分に長く維持されます。

    しかし、コードが代わりにデータのコピーを 作成したと想像してみてください。 新しい配列に格納されます。 この配列はローカル変数に格納されます。 そして、そのコピーから スパンを返そうとします。 コンパイラはここでエラーを生成します。

    その理由は、新しく作成された配列が ローカル変数に格納されるためです。 それが、この事業を存続させている要因だ。 呼び出し元までスパンをローカル変数に 返すことはできません。 なぜなら、ローカル変数は 終了するとすぐに消滅してしまうからです。 Cの観点から考えると、 私が話している制限事項は、 聞き覚えがあるかもしれません。 ローカル変数のアドレスを取得すると 想像してみてください。 そのポインターは非常に 慎重に扱わなければなりません どこかに保存されないようにするため、 そして、関数が戻り 値を返した後に使用されます。 そしてローカル変数は消え去った。 Swiftはこれらの制約を言語の 一部として組み込んでいる。 つまり、メモリの安全性を損なうようなミスは 許されないということです。

    それ自体で、メモリへの読み 取り専用アクセスを提供します。 可変アクセスを提供する 別のタイプの可変スパンがあります つまり、あなたは書くことも 読むこともできるということです。 連続する任意の要素から 可変スパンプロパティを使用できます 先ほど説明したコレクションは、 不変のスパンをストレージに 取り込むためのものです。 そして、予想通り、添え 字を使ってそこにある要素を変更します。

    さて、ここでの安全モデルの 重要な部分は、可変性です span は、基となる メモリへの排他的アクセスを必要とします。 つまり、メモリブロックを参照する 不変スパンがある場合、 他の誰もその同じ記憶に アクセスすることはできません。 書くためでも読むためでもない。

    そのため、コードでは、 同じ配列内部にアクセスする 2つ目のスパンを作成する そして突然変異を起こそうとする、 コンパイラはここでエラーを生成して、 いかなるアクセスも阻止します。 変異がまだ活発な状態にある間に、 ストレージに保存する。

    この排他性モデルは Swiftにとって不可欠なものです。 実はそれは最初から実施されていたんです。 これは、ミューテーションメソッドなどを 使用する際に メモリの安全性を確保するものです。 および入力パラメータ。 ほとんどのSwiftプログラマーは、 それが存在することすら知らない。 非常に稀なことだからです 実際にメモリ安全違反を引き 起こすような状況に遭遇すると、 しかし、それはメモリの安全性を確保するための 最終手段として存在している。 さて、それでは可変スパンを 採用する時が来ました。 ランレングス復号関数では、ヒープを 返す代わりに 割り当てられた配列。これは スパンよりも少し手間がかかる。 しかし、ここでもまた、 関数のシグネチャから始めましょう。 ここで重要なのは、返される 新しいストレージを作成する代わりに、 発信者へ。発信者は、 どこにいるか教えてくれます。 結果をこの出力パラメータ経由で出力します。 可変スパンを変更すると、それが渡されます。 結果はそこに送られます。 また、出力配列に追加する代わりに、 ピクセルは直接書き込まれる このアウトパラメータを通して、 それらを最終的な位置に移動させます。 これは、この関数内でメモリ割り 当てが行われなくなったことを意味します。 読み取りバッファと書き込み バッファの設定はすべて呼び出し側次第です。 Cでやったのと同じように。 発信者について言えば。 つまり、以前は実際に 早期デコードが配列を返したという 事実に基づいて。 それでは、もう一度その点について 見ていきましょう。 では、この関数に必要なものは やるべきことは、独自のピクセル配列を 割り当てることです。 そして、可変スパンをその配列に 渡してLEDコードに渡します。 結果として得られたピクセルを埋める。

    もちろん、この呼び出し元は ヒープ割り当てを行うことを選択しています。 しかし、別の電話をかけた人であれば、 全く異なる選択をするかもしれない。

    ここに例を示します。 この構造は320を表しています 240ピクセルのフレームバッファ。 ヒープメモリの割り当てを避けるため、 インライン配列として表現されます。

    画像デコード操作は可変参照を受け取ります フレームバッファには、Inout を 使用して再度渡されました。 すると、それらのピクセルに 不変のスパンが入ります そして、その情報をLEDデコードに渡します。

    ここで何が起こっているか分かりますか? デコードされたデータは フレームに直接書き込まれます。 いいえ。余分なコピーは作成しません。 メモリも割り当てません。

    spanを採用することは、 パフォーマンスとメモリ安全性の両面において 大きなメリットとなる。 Swiftコードベースにぜひ取り 入れていただくことをお勧めします。 スパンを採用する 必要がある場所を探している場合、 出発点は2つある。 パフォーマンスの観点から言えば、 配列やデータ型を使用している、パフォーマンスに 影響するコードを探してください。 余分なコピーやヒープ割り 当てに気づいた場合は、 代わりに span を使用してください。 デコード操作で行ったのと同様です。

    メモリの安全性という観点から、 まず、コード内で安全でないバッファポインタ型を使用している 箇所を置き換えることから始めましょう。 その名前が示すように、 安全でないポインタ型は メモリの安全性を維持しません そして、使用頻度は極めて低いべきである。 Span は、ほとんどの安全でない ポインタの使用において安全な代替手段です。 ただし、そこに至るまでには多少のリファクタリングが 必要になるかもしれません。 それでは、同僚のフェリックスに バトンタッチして、 対処法についてさらに詳しく 説明してもらいます。 メモリ安全性を損なうことなく、 Swiftで安全でない構造を使用する。

    ありがとう、ダグ。

    こんにちは、フェリックスと申します。 セキュリティエンジニアリング部門に 所属しています。 そして、建築チーム。 次の議題は、安全でない コードを安全に利用することです。

    今や、メモリ安全な言語こそが プログラミングの未来だ。

    ダグが説明したように、 スパンなどのオーバーヘッドの少ない プリミティブを使用することで、 安全なコードは非常に高速であり、 メモリ安全性のバグを引き 起こすこともありません。

    同時に、安全でないコードは今日、 至るところに存在している。 文字通り。

    安全な言語は、これまで使いにくかった 地域でも普及しつつある。 以前はそうではなかった。依然として 数十億行もの安全でないコードが残っている。 これは何十年も前から知られていることだ。

    残念ながら、それは一般的な工学の常識であり、 根本から間違っている。 書き換えは危険です。 新しい実装ではバグが新たに発生したり、 再発したりする可能性があります。 そして既存の実装が同時に 進化し続ける場合安全でない実装として、 それはそれと競合します。

    だからこそ計画を立てることが重要なのです 安全でないコードから段階的に移行するために、 より小さな範囲で書き換えを行う。 リスク管理がはるかに容易になる そして成功の可能性は飛躍的に高まる。

    そして、これが今日重要な理由は、 Swiftには独自の C、 C+ +、 Objective-Cも 可能です。

    これらのツールの1つ目は、 厳格なメモリ安全性です。 これ以上に安全な働き方はない 安全でないコードを使用するよりも、 厳格なメモリ安全性を有効にする方が安全です。 これは非常に重要です。

    厳密なメモリ安全性は、安全でない コードの使用箇所をすべて明らかにする。 これは非常に便利です。なぜなら、 Swiftでは、安全でないものに unsafeという名前がよく付けられますが、 一部の操作は暗黙的に安全ではありません。

    例えば、このコードでは、 配列のコピー関数は、 2 つの配列変数 x と y を宣言します。 そして、memcpyを使って 一方から他方へコピーします。

    コードには Memcpy が 安全でないことをするとは書かれていません。 しかし、MemcpyはC言語の関数です。 そのため、安全でない ポインタを受け入れます x および y は暗黙的に安全でない ポインタに変換されます。 これは、明確な兆候もなくメモリ安全性の バグを引き起こす可能性があります。

    厳密なメモリ安全性を有効にすると、 コンパイラは警告を発します。 これおよびその他すべての安全でない コードの使用について 式は安全でない構造を使用しますが、 安全でないとマークされていません。

    これは、呼び出しの前に unsafe キーワードを追加することで解決できます。

    少し時間をいただいて詳しく説明します コンパイラのアドレス指定以外で unsafe キーワードを使用すること。 注意:主な機能は2つあります。

    まず、これはコードベースを監査する 際のセキュリティレビュー担当者への警告です。 unsafe キーワードは、潜在的に何かが 危険な事態が起きている。

    そして第二に、さらに重要なことに、 これは、コンパイラが 検証できないことを検証する 必要があることを思い出させるものです。 確認するため。

    Memcpyの例に戻って、 どちらの配列も4バイトを含んでいるため、 コードは正しい。 しかし、コンパイラはこれが呼び 出しの前提条件であることを認識していません。 unsafe キーワードは、 Memcpy が正しく使用されている ことを確認するための注意喚起です。

    Xcodeプロジェクトで有効にするには。 Swift言語オプションの中から、 厳密なメモリ安全性設定を探してください。

    Swiftパッケージでは、厳密なメモリ安全性は、 追加することで有効になります。 パッケージの説明にある厳格なメモリ安全設定。

    厳密なメモリ安全性が有効になっている場合でも そして、安全でない コードが可視化されるようにします。 やはり、安全でない機能は 一切使用しないのが最善策です。

    安全でないコードが本当に 必要なケースは2つしかない。 まず、安全でないライブラリとの 相互運用性を確保するため

    そして2つ目は、安全なプリミティブを 実装することです。 多くの場合、同じ小さな危険な宝石には、 実は二つの側面がある。

    安全な言語で新しいコードを書くことは 多くの利点があります。 しかし、安全でない実装でも、 安全でない実装は依然として 最良のツールである可能性がある 一部のタスクの場合。

    これは、安全でないライブラリが一般的であり、 セキュリティとは別に、 おそらく最も成熟しているだろう。

    安全でないライブラリを安全な言語で 書き直すことが可能であれば、そうする。 それは常に望ましいことです。 しかし、それは必ずしも 任意の時間枠で可能とは限らない。 安全な書き換えには時間と専門知識が必要 専門知識も利用可能です。 Swiftは、ライブラリが安全に 利用されることを保証するのに役立ちます。

    ダグは先ほどデコード機能を紹介しました。 実装されたとしましょう 容易に書き換えられない 外部Cライブラリ内に存在する。

    Swift がヘッダーを見ると、 関数をこのように公開します。 安全でないインターフェース。ソースポインタと 同じパラメータを受け取ります。 ソースサイズ、宛先ポインタ、および宛先数。 そして、安全でない値を使用している ため、理想的ではありません。 しかし、Swiftから 呼び出すことは可能です。

    しかし、厳密なメモリ安全性が 有効になっている場合、 コンパイラは同じ安全でない構造を出力します。 警告。

    安全でないものを安全なラッパーで ラップする方が良い ダグが示したような実装方法。 このラッパーは、入力としてスパンを受け取り、 出力として可変スパンを受け取ります。 そのラッパーには「安全でない」 という表現がたくさん含まれているでしょう。 これは、スパンから ポインタを取り出す各操作がまたは、 それらのポインタを使用するものは、 安全でないとマークする必要があります。 しかし、セキュリティ監査は容易である。

    このコードは各スパンから 安全でないポインタを取り出し、 そして、対応するカウント値とともに C言語の実装に渡します。

    Swiftインターフェースのユーザーを 監査する必要はありません。 なぜなら、それは橋桁を通過させることが でき、橋桁は安全だからだ。 ここに間違いはないが、 もし間違いがあったとすれば、 それはこの実装において実現されるだろう。 C言語による実装にメモリ安全性のバグが 存在する可能性もある。 しかし、呼び出し元のSwiftモジュールは 不正行為をしていないと判断された。 赤いコードが安全な実装を得たとき。 このリスクは完全に排除されます。

    さて、安全なプリミティブを実装する 側から見ていきましょう。 他に起こりうる事態安全でない コードをラップする場合、外部ライブラリが 販売されている可能性があります。 手動で作成および削除する 必要のあるリソースの一種。

    デコード関数をもう一度示します。 単一のステートレスなデコード関数ではなく、 次に、RL を含む デコーダーオブジェクトを作成する 必要があります。 そして、RL destroyでそれを 破壊する必要があります。

    そしてRLデコード機能は以前とほぼ同じです。 しかし、現在は最初の引数として デコーダーを受け取るようになっています。

    このパターンでは明示的なDNNが必要です。 コピー可能な構造体には DNNを持たせることができないからです。 これは常にクラスを使って実装されていました。 現在、安全でないリソースをカプセル化する コードの多くは、 このような形をしています。

    初期化子はRL初期化関数を呼び出す。 そして、初期化関数が破棄関数を呼び出します。 デコード機能は以前とほぼ同じです。

    これは機能するが、 もっと効率的にできるはずだ。

    第一級インスタンスは動的に割り当てられます。 これは通常、長寿命の物体にとっては 問題になりません。 しかし、インスタンスを繰り 返し作成および破棄すると、 mallocとfreeへの 回避可能な呼び出し。 動的割り当てを使用すると、 さらにコストがかかります。 別の動的割り当てをラップする。

    セカンドクラスのインスタンスは 参照カウントされます。 これにより、複雑なメモリ管理状況でも 安全性が維持され、 しかし、物によっては支払うことになる 参照カウントトラフィックの場合、 たとえライフタイムが非常に単純であっても。

    最後に、クラスインスタンスのすべてのフィールドには、 きめ細かな排他性チェックが 行われます。実行時に、 これにより、より柔軟なエイリアシング操作が 可能になります。 構造体について。しかし、繰り 返しますが、単純な操作を行うタイプは、 全く恩恵を受けず、コストを 負担することになるかもしれない。 クラスインスタンスは非常に汎用性が高いが、 必要以上に肥大化する可能性がある。 これらは小さな間接費です。 しかし、全くチェックを行わない 安全でない実装と比較すると、 それらはすぐに積み重なる。

    Swift 6以降では、 これらのユースケースで コピー不可能な構造体を使用できます。

    構造体は動的メモリ割り当てを必要としません。 これで、管理コストの要因が一つ減りました。 そして、彼らはコースの独占性チェックを 行っており、そのほとんどは検証可能です。 コンパイル時に処理されるため、 プログラム自体に最初から 存在する要素の数が少なくなります。 そして、それらは 最適化によって簡単に排除できる。

    しかし、コピー不可能な 構造体を共有することは、 クラスを共有するよりもはるかに制約が多い。 またはコピー可能な構造体、

    decode one関数における参照型の 柔軟性のおかげです。

    同じデコーダーへの参照が 複数あっても問題ありません。 そして、どちらか一方を通して decodeメソッドを呼び出します。

    しかし、コピー不可能な構造体で 同じことを行うのは誤りです。 コンパイラは、オブジェクトAがBに 移動されたことを即座に診断するだろう。 そして再び使用された。

    つまり、単純なオブジェクト管理の場合、 コピー不可能な構造体は、クラスに比べて パフォーマンス面で多くの利点があります。 柔軟性に欠けるため、 常に使用できるとは限りません。 より具体的ではありますが、 その代わりに、より予測可能な パフォーマンスが得られます。

    私が一番望まないこと 話したいのは、C からSwiftを 呼び出すことです。

    現在、主要なプラットフォームはすべて 安全でないCまたは C+ + コアを持っています。 そして、すべての安全な言語は、 そのコアにアクセスする必要がある。 どういうわけか。C言語との混在は、 安全な言語にとって正常かつ当然の機能である。 いずれにせよ、それはしばしば困難を伴う。

    難しい理由の一つ

    言語によって期待が異なるということです。 そして、ある言語が 別の言語に電話をかけるとき、 両言語の期待値は維持されなければならない。 例えば、ガベージコレクションを 使用する言語では、 オブジェクトポインタをC言語に渡すには、 特別な協力が必要になる場合があります。 オブジェクトが静止している間は ガベージコレクタが移動しないようにする。 C言語からの参照。また、ほとんどの言語が お互いのことをあまりよく理解していない。 例えば、C言語を呼び 出すことができる多くの言語では、 相互運用にはグルコース( C言語の単位)が必要です。 これはCヘッダーファイルの説明です ターゲット言語コンパイラはCヘッダーを読み 取ることができないため、 そのコードを書くのは面倒だ。

    しかし幸いなことに、 Swiftは安全でない 言語との相互運用性を考慮して設計されている。

    Swiftはそうした複雑さのほとんどを 解消する 開発者向けには、Cコンパイラ全体を組み 込むことで実現する。

    ヘッダーファイルから任意の宣言を解釈して 利用可能にすることができます。 インライン関数も含め、 ブリッジングヘッダーから解析して取得します。 プロジェクトには、ブリッジングヘッダーから の任意のヘッダーを含めることができます。

    Swift は宣言を利用可能にすることが できます Cコンパイラに対しては、 独自のヘッダーを生成することで対応します。

    ダグが以前紹介したデコードの例を、 画面に再び表示します。 ダグは、spanを使った実装が 最も柔軟な選択肢であることを示した。 その実装は独自のバックエンドとして 使用されました ピクセルを全く異なる方法で返す 他の2つの関数についても同様です。 配列を返す最初のもの、 そして2つ目は、 出力を参照渡しで返すものです。 モードXフレーム構造に組み込む。

    Swift 6.3以降、 span の実装は C 関数のバックエンドにもなり得る。 例えば、ダグが最初に使ったようなものだ。

    これは、ダグが紹介したC言語による実装です。 最後にもう一度じっくり見てみよう なぜなら、それを削除して Swiftの実装に置き換える予定だからです。

    これを行うには、まず 互換性のあるプロトタイプを 持つSwift関数であること 対象となるC関数を使用します。

    ここには、入力ポインタ、 アカウント、出力ポインタ、 アカウント、そして、 入力ポインタと出力ポインタに スパンを作成します。 そして、共通の準備済みコードである Swiftバックエンドを呼び出します。 次に、その関数をC言語に公開する必要があります。 それには2つの方法があります。

    まず一つ目は、関数に 「at c」属性を追加することです。

    C言語で使用する場合、 Swiftは型を変換します。 妥当な対応するC型へ。 例えば、SwiftのInt32型は int32t型に変換されます。 基本的な整数型の型定義が、期待される 対応する型に変換されることを確認します。 チャートの開始部分をご覧ください。 ご覧ください。 ショートからショートへ。 エンドからintを参照。 など。int はポインタ div t に 変換されることに注意してください。そして。 これが、私たちのコードが受け入れる理由です 実装時には、サイズ t の代わりに ポインタ div t を返します。 実装する関数が既にブリッジングヘッダーで 確認できる場合。 C言語の実装と組み合わせる 2つ目の選択肢があります。 Objective-Cメソッドを使用する場合 生成されたヘッダーに宣言を出力するのではなく、 実装時に宣言を出力する。 これはコンパイラに 既存の宣言を探すように指示します。 ブリッジングヘッダーからのデコード機能用。

    この方法を使用する場合。 コンパイラは、Swiftプロトタイプが C プロトタイプと一致することを検証します。 互換性がない場合はエラーが発生します。

    C だけを使用する場合、 Swift は 引数の型を選択する必要があります。 しかし、C言語での実装で使用する場合、 他のいくつかの変換にも対応できる。 例えば、Cプロトタイプが サイズTを使用する場合、 Swiftは、Uintの代わりに intを受け取る実装も受け入れます。

    さて、これは今起こったことを振り 返る絶好の機会です。 私の右側には、cats という 名前の C 関数があります。 そして、写真に写っているペットを 識別する犬もいます。

    画像構造へのポインタを受け取ります そして、ペット記録のバッファへのポインタ。 画像の解凍のために ピクセルメモリを管理します。 そして、デコード関数を呼び 出して画像を解凍します。 そして最後に、猫と犬を識別するために、 猫がどこにいるかを特定します。 そして、写真には犬も写っている。

    以前は、C言語による読み取り コードの実装を呼び出していました。 右側には、先ほど犬たちが 示していた姿が写っている。 しかし、何も変更せずに C言語の実装を使用することで 学者によると、猫は また、dogs機能は現在、 安全な赤コード実装を使用しています。

    そしてこれはSwiftから シームレスに動作しました Swiftコンパイラはデコード実装を 一致させることができるため clangが赤色のコードとして認識するのと 同じC関数プロトタイプを使用します。

    Cに必要なのはそれだけです そして実装段階では、 C言語のコードベースをSwiftに 移行するための優れたツールとなります。 そして、安全な言語で新機能を開発する C言語の呼び出し元で 使用される必要がある場合。

    これで、スパンの移動のみのタイプと C間の相互作用について学びました。 そして Swift、 次にやるべきことは次のとおりです。 まず、コード内で厳密なメモリ安全性を 確保してください。

    これにより、コードベース内の 安全でない操作を考慮に 入れることができるようになります。 次に、spanを使用して連続メモリに 安全にアクセスする方法を学びましょう。 まず、安全でないバッファポインタの使用箇所を 置き換えることから始めましょう。 次に、安全でないリソースをカプセル化して、 安全なインターフェースを作成します。 可能な場合は移動専用型クラスを使用し、 そうでない場合は別の方法を使用する。 そして最後に、安全でない コードを徐々に移行し始めましょう。 Swiftの相互運用機能を利用して Swiftに連携させる。 ご清聴ありがとうございました。 メモリの安全性の欠如は、 今日のセキュリティバグの最大の原因です。 そして、共に、より安全な世界を築いていくことを 楽しみにしています。

    そして、本日の最後のプレゼンテーションに 移ります。短いプレゼンテーションです。 Xcodeでサニタイザーを 使用するための実践的な概要 コードのバグを突き止めるため。 ダンをステージにお迎えしましょう。

    こんにちは、ダンですAppleで ソフトウェアエンジニアをしています。 私はセキュリティツールチームに所属していて、 サニタイザーの開発を担当しています。 今日はセキュリティバグの発見について お話しするために来ました 既存のコードにサニタイザーを 追加してください。

    このプレゼンテーションでは、 消毒剤の概念についてご紹介します。 そして次に、そのうちの2つ、 消毒剤についてお話しします。 そして糸消毒剤。これらは 最も強力な消毒剤の2つです。

    まず最初に、その基本的な 概念について説明します。

    消毒剤は、害虫を発見するための道具である。 それらは、追加の簿記処理や 実行時チェックをコードに組み込みます。 厳密な実行時チェックのため、 それらは、あなたが気づいていない バグを発見するのに役立ちます 顧客に影響が出る前に。

    それらは非常に貴重なものにもなり得る 一見不可能に思える 事故報告の根本原因を突き止めるため。

    消毒剤とは何かを定義したので、 次に住所消毒剤について説明します。 大まかに言うと、アドレスサニタイザーが エラーを検出してスローします プログラムがメモリを不正に使用した場合。

    guard malloc のようなツールとは異なり、 ヒープ メモリの問題のみを検出します。 アドレスサニタイザーは、スタック領域や グローバル変数領域の問題も検出できます。 また、チェックに バイトレベルの精度を提供します。 つまり、ほんのわずかな範囲外アクセスでも 検知されるということだ。 対処すべきバグの種類をいくつか 見ていきましょう。 消毒剤が見つかる。

    このコードスニペットでは。 このNsstring変数の元の コピーを作成する予定です。 一見分かりにくいかもしれませんが、 メモリ範囲外アクセスに関する バグが存在します。

    その理由をここで説明します。 右側に示されている元のデータの基となる バイトへのポインタを取得します。

    そして、コピー用に元のドット長分の バイトを割り当てます。

    そして、ここから事態は悪化し始める。

    元のドット長ではバイト数はわかりません。 実際にはUTF-16コードユニットの 数が表示されます。 そして、手を振る絵文字は、 これら2つで構成されています。

    つまり、生のコピーは5バイトの割り 当てを指していることになる。

    次に、元の生データから コピーデータにバイトをコピーします。 しかし、最後の2バイトは 割り当て範囲外になります。 これはまさに、見落としやすい 厄介なバグの一例だ。 そして悪用される可能性がある。

    幸いなことに、アドレスサニタイザーはそして、 ここでバッファオーバーフローが 発生する可能性があると警告してくれます。 アドレスサニタイザーによって検出されたもう 1つのバグの種類は、 解放後使用(use after free)です。 この C+ + の例では、 タブの標準ベクターを保持しています。 そして、右側に現在アクティブな タブへのポインターを保持します。 ベクトル内に1つの要素のためのスペースが 確保されていることがわかります。 しかし、まだ人口は増えていない。

    最初のタブのメールを開き、 それをアクティブなタブに設定しました。

    それから別のタブを開きます。 ニュース。これによりベクターは 能力を拡大せざるを得なくなる。

    つまり、新しい割り当てを作成し、 そこに要素を移動させる 必要があるということです。

    残念ながら、この事態が発生した際に アクティブ状態は更新されませんでした。 そして現在は、解放された メモリを指しています。

    アクティブアドレスによってタブポインタを 再読み込みしようとすると サニタイザーは、割り当て解除された メモリの使用を示すエラーをスローします。

    例に示すように。 Objective Objective-C Objective-Cがすべて サポートされています。 これには、手動および 自動の参照カウントが含まれます。

    最後に、 Swiftもそうです。 純粋なSwiftでは、 メモリの不正使用はまず起こらないだろう。

    しかし重要なのは、 Address Sanitizerは 多言語に対応している点です。 ここにSwiftの 配列numbersがあります。

    C言語の関数からこの配列を使用するには、 安全でないバッファポインタを取得します。 ポインタnumsは配列の最初の要素を 指していることに注意してください。

    それでは、合計関数を呼び出します。 そのためには、配列の先頭へのポインタと 配列の長さを渡す必要があります。

    sum関数は配列の各要素を 反復処理して合計します

    しかし、私はここで 典型的な間違いを犯してしまった。 Len 未満の間反復する代わりに、 以下を使用しました。 その結果、最終反復では 範囲外の値が出てしまうでしょう。

    アドレスサニタイザーはこれを検知し、 バッファオーバーフローに関する エラーをスローします。 これは、C言語の 境界安全拡張機能はこれを解決します。

    住所消毒剤について知っておくべきことは 以下のとおりです。 まず、これは開発時のみに使用するものであり、 実行時のセキュリティ強化を 目的としたものではありません。

    これほど強力なツールにしては。 メモリ使用量と実行時のオーバーヘッドはそれぞれ 約2~3倍と少ない。

    テスト中に発生するバグを、 それが製品に反映される前に 見つけるのに非常に優れています。 顧客にとって重要なことなので、 できる限り多くのテストを行うことが大切です。 有効にすると、

    ユニットテストやUIテストなどの 自動テストで有効にします。 開発中に手動テストを行う際に有効にする。 そして、そのツールを最大限に活用するため。 エッジケースや稀なケースをトリガーすることは 非常に重要です。

    開発中にアドレスサニタイザーを 有効にするため。 まず、製品メニューを開いて スキーマエディタに移動します。 次に、スキームのサブメニューを開き、 「スキームの編集」を選択します。

    ここから「実行スキーム」に移動します。 次に、「診断」タブで「アドレスサニタイザー」 チェックボックスをオンにします。

    テストプランでアドレスサニタイザーを 有効にするには。 製品メニューを開き、 「テスト計画」を選択して 「テスト計画の編集」をクリックします。

    設定タブを開き、「ランタイムサニタイズ」 セクションまでスクロールしてください。

    次に、「アドレスサニタイザー」の行を選択し、 「オン」に設定します。

    それでは、アドレスサニタイザーをテストに 利用する方法を説明します。

    さて、これが複数の言語を使った例の スライドにある私のコードです。 Swift配列の数値を取得します。 次に、安全でないバッファポインタをこれに 対して取得しますそして、 その中で私のC言語関数である sumを呼び出します。 各要素を順番に処理して合計します。 そして結果をSwiftに返します。

    そして、配列と結果を出力します。 それでは、早速実行してみましょう。

    まず、私のプログラムが正常に 実行されたことが確認できます。

    しかし、この値は明らかに正しくありません。

    それでは、プロダクトスキームの編集スキームで アドレスサニタイザーを有効にします。 また、「アドレスサニタイザー」チェックボックスを オンにすることでも構いません。

    つまり、実行ボタンをクリックすると、 サニタイズ処理を施した 状態で再構築されるということです。 そしてすぐに、何かが捕まったのが分かった。 この行でヒープバッファオーバーフローが 発生しました。

    左側には、この結果に至ったコールスタックが 表示されています。 これがすぐにわかることも64バイトの ヒープ割り当て後。 このスライドメニューでは、 割り当てがどこにあったかを確認できます。 そして当然のことながら、 それは私がそのSwift配列を 構築したときのことです。

    スタックフレームに戻しました。 私はライブデバッグセッション中です そうすれば、変数の現在の値を確認できます。 私はレンと同じだとわかります。 これは、ループ境界条件に何か 問題があることを示しています。 私のスライドで説明したとおりです。 それは、ここに余分な等号があるからです。 だから、それを削除して アプリケーションを再構築する。

    正常に実行されたかどうか確認してみます。 さらに、合計値も正しく 取得できるようになりました。

    はい。では、スライドに戻ります。

    次に紹介する消毒剤は、 フレッド・サニタイザーです。

    Fred Sanitizerは、 データ競合やその他の並行処理上の 問題を検出します。

    データ競合は、ある スレッドがメモリの場所に書き込み、 そして、別のスレッドが 同期せずに同じメモリ位置にアクセスする。

    右側のコード例では、 保留中のキューから先頭を取得し、 送信し、解放し、その後ヘッドを インクリメントする。 同じことをする別のスレッドが存在するまでは、 これは問題なく動作します。 現在、ワーカー スレッドが 2 つあります。 そして、ここに考えられる 操作のインターリーブの例を示します。

    フレッドは値ゼロのヘッドを読みます。

    フレッド2は、値ゼロのヘッドも読み取ります。

    Fredは保留中のメッセージを送信し、 オブジェクトを解放します。

    そして、headの値を1に増やします。

    これがデータ競争だ。 フレッド2での読み取りとフレッド1での 書き込みがどちらの順序で 行われるかによって異なります。 この場合、 Fred 2 のインデックスの値は 異なる可能性があります。 Fred 2 の古いヘッド値により、 保留中のゼロと読み取られます。 フレッドによって解放されたばかりのアドレスサニタイザーが 使用を検出します 発生した後、ここで無料になります。 そしてこの実行において、 解放後の利用が発生した。

    これは同じ2つのスレッドで 実行されている同じコードです。 しかし今回は、それらの間に インターリーブ操作はありません。 アドレスサニタイザーはこの実行における 問題を検出できません。

    でも朗報です。予想通りの結果でしたが。 スレッドサニタイザーは依然として 問題があることを検知し、私に警告を発します。 このスレッド2の読み 取りはデータ競争の一部です。 また、Fred Sanitizerは、 競合しているメモリアクセスも 表示してくれます。

    これはスレッド1に書き込まれています。 だからこそ、糸消毒剤は非常に役立つのです。 再現性がないように見える バグ報告の根本原因を突き止めるため。

    この問題を解決するために、私は シリアルディスパッチキューを使用します。 これらの各セクションがアトミックに実行され、 読み取りがそして、 先書きは右側で同期されます。 これらをdispatch asyncで ラップしました。 そして、それらは専用のシリアルキュー上で 実行されます。

    Swiftの並行処理を使用することで、 データ競合を防止できます。

    スレッドサニタイザーは、アドレスサニタイザーと 同様の方法で有効化されます。

    この2つは相互に排他的であることに 注意してください。 そのため、一度に 有効にできるのは1つだけです。

    自動テストの場合、 テストプラン用に2つの異なる 構成を作成できます。 1つはアドレスサニタイザーを 有効にした状態で、 もう1つはスレッドサニタイザーを有効にした 状態で設定されています。

    サニタイザーは、メモリの完全性を確保する 上で重要な役割を果たす。

    アドレスサニタイザーは、無効なメモリアクセスを 検出して修正するのに役立ちます。 これらは、Emmyが有効になっている場合に クラッシュを引き起こします。 スレッドサニタイザーはデータ競合を 見つけるのに役立ちます。 これはしばしば、フリーキック後の 利用につながる。

    幸いなことに、Emmy は 解放後の使用が発生するとクラッシュを引き 起こします。搾取を防ぐしかし、 それは顧客にとって不満の原因となるでしょう。

    スレッドサニタイザーを使用して バグを見つけて修正することで、 顧客の安全を守ることができます。 そして幸せだ。

    次にすべきことは以下のとおりです。 まず、 Address Sanitizer に アクセスしてテストプランの設定を行い、 特に、コードベースでC、 C+ +、 またはObjective-Cを 使用している場合はなおさらです。

    次にスレッドサニタイザーへ C言語や事前並行処理を使用している場合は、 テスト計画にその旨を記載してください。 Swift。

    Swiftコードにおけるデータ競合を 防ぐために、 Swiftの並行処理機能を採用しましょう。 そして最後に、次に説明のつかない 事故報告を受け取ったときは または、再現性がある場合は、 消毒剤を取り出して、問題が 検出されるかどうかを確認してください。 もしかしたら、彼らはなぜそのような 劣悪な状態に至ったのか、 その手がかりを与えてくれるかもしれない。 ありがとうございました。それでは、 カートさんにお話を伺います。

    ダン、ありがとう。これで 今日のプレゼンテーションは終了です。 プレゼンターの皆様、 本当にありがとうございました。

    本日取り上げた内容を補足すると、 開発についてもっと学ぶための最良の方法の1つ Appleプラットフォーム向けの情報は WWDCの動画を通じて提供される。 その他、Apple主催の イベントも開催されます。 何百もの動画があり、 それらはAppleデベロッパの ウェブサイトまたは デベロッパアプリで視聴できます。 見覚えのある顔ぶれに出くわすかもしれません。

    開発者センターにお越しいただいた皆様、 そしてオンラインでご参加いただいた 皆様、ありがとうございました。 それでは、オンラインでさよならを言います。 さよなら。 そして、ここにいらっしゃる皆様には、 ロビーで軽食をご用意しておりますので、 ぜひご参加ください。 そして、とても楽しい会話でした。 ありがとうございました。

デベロッパ向けフッタ

  • ビデオ
  • Meet with Apple
  • アプリの強化:セキュリティを向上させるための必須戦略
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    メニューを開く メニューを閉じる
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • AIと機械学習
    • Apple Intelligence
    • オーディオとビデオ
    • 拡張現実
    • ビジネス
    • デザイン
    • 配信
    • 教育
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内購入
    • ローカリゼーション
    • マップと位置情報
    • セキュリティ
    • Safari/Web
    メニューを開く メニューを閉じる
    • ドキュメント
    • ダウンロード
    • サンプルコード
    • ビデオ
    • ドキュメントのアーカイブ
    メニューを開く メニューを閉じる
    • ヘルプガイドと記事
    • お問い合わせ
    • フォーラム
    • フィードバックとバグの報告
    • システムステータス
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(証明書、ID、プロファイル)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • セキュリティ報奨金プログラム
    • Security Research Device Program
    メニューを開く メニューを閉じる
    • Appleに相談
    • Apple Developer Center
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academy
    • WWDC
    最新ニュースを読む
    Apple Developerアプリを入手
    bilibili、LinkedIn、WeChat、YouTubeでフォロー
    Copyright © 2026 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン