sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget'/translations/zh_CN/userspace-api/msealmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget'/translations/zh_TW/userspace-api/msealmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget'/translations/it_IT/userspace-api/msealmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget'/translations/ja_JP/userspace-api/msealmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget'/translations/ko_KR/userspace-api/msealmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget'/translations/sp_SP/userspace-api/msealmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageEnglishuh1h hh _documenthsourceNlineNubhcomment)}(h SPDX-License-Identifier: GPL-2.0h]h SPDX-License-Identifier: GPL-2.0}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhhA/var/lib/git/docbuild/linux/Documentation/userspace-api/mseal.rsthKubhsection)}(hhh](htitle)}(hIntroduction of msealh]hIntroduction of mseal}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh field_list)}(hhh]hfield)}(hhh](h field_name)}(hAuthorh]hAuthor}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh field_body)}(hJeff Xu h]h paragraph)}(hJeff Xu h](h Jeff Xu <}(hhhhhNhNubh reference)}(hjeffxu@chromium.orgh]hjeffxu@chromium.org}(hhhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:jeffxu@chromium.orguh1hhhubh>}(hhhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhhubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubah}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh)}(hX-Modern CPUs support memory permissions such as RW and NX bits. The memory permission feature improves security stance on memory corruption bugs, i.e. the attacker can’t just write to arbitrary memory and point the code to it, the memory has to be marked with X bit, or else an exception will happen.h]hX-Modern CPUs support memory permissions such as RW and NX bits. The memory permission feature improves security stance on memory corruption bugs, i.e. the attacker can’t just write to arbitrary memory and point the code to it, the memory has to be marked with X bit, or else an exception will happen.}(hj!hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK hhhhubh)}(hX0Memory sealing additionally protects the mapping itself against modifications. This is useful to mitigate memory corruption issues where a corrupted pointer is passed to a memory management system. For example, such an attacker primitive can break control-flow integrity guarantees since read-only memory that is supposed to be trusted can become writable or .text pages can get remapped. Memory sealing can automatically be applied by the runtime loader to seal .text and .rodata pages and applications can additionally seal security critical data at runtime.h]hX0Memory sealing additionally protects the mapping itself against modifications. This is useful to mitigate memory corruption issues where a corrupted pointer is passed to a memory management system. For example, such an attacker primitive can break control-flow integrity guarantees since read-only memory that is supposed to be trusted can become writable or .text pages can get remapped. Memory sealing can automatically be applied by the runtime loader to seal .text and .rodata pages and applications can additionally seal security critical data at runtime.}(hj/hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hA similar feature already exists in the XNU kernel with the VM_FLAGS_PERMANENT flag [1] and on OpenBSD with the mimmutable syscall [2].h]hA similar feature already exists in the XNU kernel with the VM_FLAGS_PERMANENT flag [1] and on OpenBSD with the mimmutable syscall [2].}(hj=hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(hSYSCALLh]hSYSCALL}(hjNhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjKhhhhhKubh)}(hhh](h)}(hmseal syscall signatureh]hmseal syscall signature}(hj_hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj\hhhhhKubh block_quote)}(hX"``int mseal(void *addr, size_t len, unsigned long flags)`` **addr**/**len**: virtual memory address range. The address range set by **addr**/**len** must meet: - The start address must be in an allocated VMA. - The start address must be page aligned. - The end address (**addr** + **len**) must be in an allocated VMA. - no gap (unallocated memory) between start and end address. The ``len`` will be paged aligned implicitly by the kernel. **flags**: reserved for future use. **Return values**: - **0**: Success. - **-EINVAL**: * Invalid input ``flags``. * The start address (``addr``) is not page aligned. * Address range (``addr`` + ``len``) overflow. - **-ENOMEM**: * The start address (``addr``) is not allocated. * The end address (``addr`` + ``len``) is not allocated. * A gap (unallocated memory) between start and end address. - **-EPERM**: * sealing is supported only on 64-bit CPUs, 32-bit is not supported. **Note about error return**: - For above error cases, users can expect the given memory range is unmodified, i.e. no partial update. - There might be other internal errors/cases not listed here, e.g. error during merging/splitting VMAs, or the process reaching the maximum number of supported VMAs. In those cases, partial updates to the given memory range could happen. However, those cases should be rare. **Architecture support**: mseal only works on 64-bit CPUs, not 32-bit CPUs. **Idempotent**: users can call mseal multiple times. mseal on an already sealed memory is a no-action (not error). **no munseal** Once mapping is sealed, it can't be unsealed. The kernel should never have munseal, this is consistent with other sealing feature, e.g. F_SEAL_SEAL for file. h](h)}(h:``int mseal(void *addr, size_t len, unsigned long flags)``h]hliteral)}(hjuh]h6int mseal(void *addr, size_t len, unsigned long flags)}(hjyhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhjsubah}(h]h ]h"]h$]h&]uh1hhhhKhjoubhdefinition_list)}(hhh]hdefinition_list_item)}(hX**addr**/**len**: virtual memory address range. The address range set by **addr**/**len** must meet: - The start address must be in an allocated VMA. - The start address must be page aligned. - The end address (**addr** + **len**) must be in an allocated VMA. - no gap (unallocated memory) between start and end address. The ``len`` will be paged aligned implicitly by the kernel. h](hterm)}(h/**addr**/**len**: virtual memory address range.h](hstrong)}(h**addr**h]haddr}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh/}(hjhhhNhNubj)}(h**len**h]hlen}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh: virtual memory address range.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhK'hjubh definition)}(hhh](j)}(hhh]j)}(hXThe address range set by **addr**/**len** must meet: - The start address must be in an allocated VMA. - The start address must be page aligned. - The end address (**addr** + **len**) must be in an allocated VMA. - no gap (unallocated memory) between start and end address. h](j)}(h4The address range set by **addr**/**len** must meet:h](hThe address range set by }(hjhhhNhNubj)}(h**addr**h]haddr}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh/}(hjhhhNhNubj)}(h**len**h]hlen}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh must meet:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhK%hjubj)}(hhh]h bullet_list)}(hhh](h list_item)}(h.The start address must be in an allocated VMA.h]h)}(hjh]h.The start address must be in an allocated VMA.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK"hjubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h'The start address must be page aligned.h]h)}(hj*h]h'The start address must be page aligned.}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK#hj(ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(hAThe end address (**addr** + **len**) must be in an allocated VMA.h]h)}(hjAh](hThe end address (}(hjChhhNhNubj)}(h**addr**h]haddr}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjCubh + }(hjChhhNhNubj)}(h**len**h]hlen}(hj\hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjCubh) must be in an allocated VMA.}(hjChhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK$hj?ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h;no gap (unallocated memory) between start and end address. h]h)}(h:no gap (unallocated memory) between start and end address.h]h:no gap (unallocated memory) between start and end address.}(hj~hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK%hjzubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]bullet-uh1j hhhK"hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK%hjubah}(h]h ]h"]h$]h&]uh1jhjubh)}(h;The ``len`` will be paged aligned implicitly by the kernel.h](hThe }(hjhhhNhNubjx)}(h``len``h]hlen}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhjubh0 will be paged aligned implicitly by the kernel.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK'hjubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK'hjubah}(h]h ]h"]h$]h&]uh1jhjoubh)}(h#**flags**: reserved for future use.h](j)}(h **flags**h]hflags}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh: reserved for future use.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK)hjoubj)}(hhh](j)}(hX**Return values**: - **0**: Success. - **-EINVAL**: * Invalid input ``flags``. * The start address (``addr``) is not page aligned. * Address range (``addr`` + ``len``) overflow. - **-ENOMEM**: * The start address (``addr``) is not allocated. * The end address (``addr`` + ``len``) is not allocated. * A gap (unallocated memory) between start and end address. - **-EPERM**: * sealing is supported only on 64-bit CPUs, 32-bit is not supported. h](j)}(h**Return values**:h](j)}(h**Return values**h]h Return values}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhK6hjubj)}(hhh]j )}(hhh](j)}(h**0**: Success.h]h)}(hj%h](j)}(h**0**h]h0}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj'ubh : Success.}(hj'hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK,hj#ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h**-EINVAL**: * Invalid input ``flags``. * The start address (``addr``) is not page aligned. * Address range (``addr`` + ``len``) overflow.h]j)}(hhh]j)}(h**-EINVAL**: * Invalid input ``flags``. * The start address (``addr``) is not page aligned. * Address range (``addr`` + ``len``) overflow.h](j)}(h **-EINVAL**:h](j)}(h **-EINVAL**h]h-EINVAL}(hjWhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjSubh:}(hjShhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhK/hjOubj)}(hhh]j )}(hhh](j)}(hInvalid input ``flags``.h]h)}(hjwh](hInvalid input }(hjyhhhNhNubjx)}(h ``flags``h]hflags}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhjyubh.}(hjyhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK.hjuubah}(h]h ]h"]h$]h&]uh1jhjrubj)}(h1The start address (``addr``) is not page aligned.h]h)}(hjh](hThe start address (}(hjhhhNhNubjx)}(h``addr``h]haddr}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhjubh) is not page aligned.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK/hjubah}(h]h ]h"]h$]h&]uh1jhjrubj)}(h,Address range (``addr`` + ``len``) overflow.h]h)}(hjh](hAddress range (}(hjhhhNhNubjx)}(h``addr``h]haddr}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhjubh + }(hjhhhNhNubjx)}(h``len``h]hlen}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhjubh ) overflow.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK0hjubah}(h]h ]h"]h$]h&]uh1jhjrubeh}(h]h ]h"]h$]h&]j*uh1j hhhK.hjoubah}(h]h ]h"]h$]h&]uh1jhjOubeh}(h]h ]h"]h$]h&]uh1jhhhK/hjLubah}(h]h ]h"]h$]h&]uh1jhjHubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h**-ENOMEM**: * The start address (``addr``) is not allocated. * The end address (``addr`` + ``len``) is not allocated. * A gap (unallocated memory) between start and end address.h]j)}(hhh]j)}(h**-ENOMEM**: * The start address (``addr``) is not allocated. * The end address (``addr`` + ``len``) is not allocated. * A gap (unallocated memory) between start and end address.h](j)}(h **-ENOMEM**:h](j)}(h **-ENOMEM**h]h-ENOMEM}(hj0hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj,ubh:}(hj,hhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhK3hj(ubj)}(hhh]j )}(hhh](j)}(h.The start address (``addr``) is not allocated.h]h)}(hjPh](hThe start address (}(hjRhhhNhNubjx)}(h``addr``h]haddr}(hjYhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhjRubh) is not allocated.}(hjRhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK2hjNubah}(h]h ]h"]h$]h&]uh1jhjKubj)}(h6The end address (``addr`` + ``len``) is not allocated.h]h)}(hjyh](hThe end address (}(hj{hhhNhNubjx)}(h``addr``h]haddr}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhj{ubh + }(hj{hhhNhNubjx)}(h``len``h]hlen}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jwhj{ubh) is not allocated.}(hj{hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK3hjwubah}(h]h ]h"]h$]h&]uh1jhjKubj)}(h9A gap (unallocated memory) between start and end address.h]h)}(hjh]h9A gap (unallocated memory) between start and end address.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK4hjubah}(h]h ]h"]h$]h&]uh1jhjKubeh}(h]h ]h"]h$]h&]jjuh1j hhhK2hjHubah}(h]h ]h"]h$]h&]uh1jhj(ubeh}(h]h ]h"]h$]h&]uh1jhhhK3hj%ubah}(h]h ]h"]h$]h&]uh1jhj!ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(hR**-EPERM**: * sealing is supported only on 64-bit CPUs, 32-bit is not supported. h]j)}(hhh]j)}(hQ**-EPERM**: * sealing is supported only on 64-bit CPUs, 32-bit is not supported. h](j)}(h **-EPERM**:h](j)}(h **-EPERM**h]h-EPERM}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhK6hjubj)}(hhh]j )}(hhh]j)}(hCsealing is supported only on 64-bit CPUs, 32-bit is not supported. h]h)}(hBsealing is supported only on 64-bit CPUs, 32-bit is not supported.h]hBsealing is supported only on 64-bit CPUs, 32-bit is not supported.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK6hjubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]jjuh1j hhhK6hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK6hjubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]jjuh1j hhhK,hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK6hjubj)}(hX**Note about error return**: - For above error cases, users can expect the given memory range is unmodified, i.e. no partial update. - There might be other internal errors/cases not listed here, e.g. error during merging/splitting VMAs, or the process reaching the maximum number of supported VMAs. In those cases, partial updates to the given memory range could happen. However, those cases should be rare. h](j)}(h**Note about error return**:h](j)}(h**Note about error return**h]hNote about error return}(hjdhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj`ubh:}(hj`hhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhK>hj\ubj)}(hhh]j )}(hhh](j)}(heFor above error cases, users can expect the given memory range is unmodified, i.e. no partial update.h]h)}(heFor above error cases, users can expect the given memory range is unmodified, i.e. no partial update.h]heFor above error cases, users can expect the given memory range is unmodified, i.e. no partial update.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK9hjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hXThere might be other internal errors/cases not listed here, e.g. error during merging/splitting VMAs, or the process reaching the maximum number of supported VMAs. In those cases, partial updates to the given memory range could happen. However, those cases should be rare. h]h)}(hXThere might be other internal errors/cases not listed here, e.g. error during merging/splitting VMAs, or the process reaching the maximum number of supported VMAs. In those cases, partial updates to the given memory range could happen. However, those cases should be rare.h]hXThere might be other internal errors/cases not listed here, e.g. error during merging/splitting VMAs, or the process reaching the maximum number of supported VMAs. In those cases, partial updates to the given memory range could happen. However, those cases should be rare.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK;hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1j hhhK9hj|ubah}(h]h ]h"]h$]h&]uh1jhj\ubeh}(h]h ]h"]h$]h&]uh1jhhhK>hjubj)}(hL**Architecture support**: mseal only works on 64-bit CPUs, not 32-bit CPUs. h](j)}(h**Architecture support**:h](j)}(h**Architecture support**h]hArchitecture support}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhKAhjubj)}(hhh]h)}(h1mseal only works on 64-bit CPUs, not 32-bit CPUs.h]h1mseal only works on 64-bit CPUs, not 32-bit CPUs.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKAhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhKAhjubj)}(hs**Idempotent**: users can call mseal multiple times. mseal on an already sealed memory is a no-action (not error). h](j)}(h**Idempotent**:h](j)}(h**Idempotent**h]h Idempotent}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhKEhjubj)}(hhh]h)}(hbusers can call mseal multiple times. mseal on an already sealed memory is a no-action (not error).h]hbusers can call mseal multiple times. mseal on an already sealed memory is a no-action (not error).}(hj$hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKDhj!ubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhKEhjubj)}(h**no munseal** Once mapping is sealed, it can't be unsealed. The kernel should never have munseal, this is consistent with other sealing feature, e.g. F_SEAL_SEAL for file. h](j)}(h**no munseal**h]j)}(hjDh]h no munseal}(hjFhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjBubah}(h]h ]h"]h$]h&]uh1jhhhKJhj>ubj)}(hhh]h)}(hOnce mapping is sealed, it can't be unsealed. The kernel should never have munseal, this is consistent with other sealing feature, e.g. F_SEAL_SEAL for file.h]hOnce mapping is sealed, it can’t be unsealed. The kernel should never have munseal, this is consistent with other sealing feature, e.g. F_SEAL_SEAL for file.}(hj\hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKHhjYubah}(h]h ]h"]h$]h&]uh1jhj>ubeh}(h]h ]h"]h$]h&]uh1jhhhKJhjubeh}(h]h ]h"]h$]h&]uh1jhjoubeh}(h]h ]h"]h$]h&]uh1jmhhhKhj\hhubeh}(h]mseal-syscall-signatureah ]h"]mseal syscall signatureah$]h&]uh1hhjKhhhhhKubh)}(hhh](h)}(h%Blocked mm syscall for sealed mappingh]h%Blocked mm syscall for sealed mapping}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKMubjn)}(hXoIt might be important to note: **once the mapping is sealed, it will stay in the process's memory until the process terminates**. Example:: *ptr = mmap(0, 4096, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); rc = mseal(ptr, 4096, 0); /* munmap will fail */ rc = munmap(ptr, 4096); assert(rc < 0); Blocked mm syscall: - munmap - mmap - mremap - mprotect and pkey_mprotect - some destructive madvise behaviors: MADV_DONTNEED, MADV_FREE, MADV_DONTNEED_LOCKED, MADV_FREE, MADV_DONTFORK, MADV_WIPEONFORK The first set of syscalls to block is munmap, mremap, mmap. They can either leave an empty space in the address space, therefore allowing replacement with a new mapping with new set of attributes, or can overwrite the existing mapping with another mapping. mprotect and pkey_mprotect are blocked because they changes the protection bits (RWX) of the mapping. Certain destructive madvise behaviors, specifically MADV_DONTNEED, MADV_FREE, MADV_DONTNEED_LOCKED, and MADV_WIPEONFORK, can introduce risks when applied to anonymous memory by threads lacking write permissions. Consequently, these operations are prohibited under such conditions. The aforementioned behaviors have the potential to modify region contents by discarding pages, effectively performing a memset(0) operation on the anonymous memory. Kernel will return -EPERM for blocked syscalls. When blocked syscall return -EPERM due to sealing, the memory regions may or may not be changed, depends on the syscall being blocked: - munmap: munmap is atomic. If one of VMAs in the given range is sealed, none of VMAs are updated. - mprotect, pkey_mprotect, madvise: partial update might happen, e.g. when mprotect over multiple VMAs, mprotect might update the beginning VMAs before reaching the sealed VMA and return -EPERM. - mmap and mremap: undefined behavior. h](h)}(hIt might be important to note: **once the mapping is sealed, it will stay in the process's memory until the process terminates**.h](hIt might be important to note: }(hjhhhNhNubj)}(ha**once the mapping is sealed, it will stay in the process's memory until the process terminates**h]h_once the mapping is sealed, it will stay in the process’s memory until the process terminates}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKNhjubh)}(h Example::h]hExample:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKQhjubh literal_block)}(h*ptr = mmap(0, 4096, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); rc = mseal(ptr, 4096, 0); /* munmap will fail */ rc = munmap(ptr, 4096); assert(rc < 0);h]h*ptr = mmap(0, 4096, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); rc = mseal(ptr, 4096, 0); /* munmap will fail */ rc = munmap(ptr, 4096); assert(rc < 0);}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKShjubj)}(hhh]j)}(hBlocked mm syscall: - munmap - mmap - mremap - mprotect and pkey_mprotect - some destructive madvise behaviors: MADV_DONTNEED, MADV_FREE, MADV_DONTNEED_LOCKED, MADV_FREE, MADV_DONTFORK, MADV_WIPEONFORK h](j)}(hBlocked mm syscall:h]hBlocked mm syscall:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK_hjubj)}(hhh]j )}(hhh](j)}(hmunmaph]h)}(hjh]hmunmap}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKZhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hmmaph]h)}(hjh]hmmap}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK[hjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hmremaph]h)}(hj(h]hmremap}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK\hj&ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hmprotect and pkey_mprotecth]h)}(hj?h]hmprotect and pkey_mprotect}(hjAhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK]hj=ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h~some destructive madvise behaviors: MADV_DONTNEED, MADV_FREE, MADV_DONTNEED_LOCKED, MADV_FREE, MADV_DONTFORK, MADV_WIPEONFORK h]h)}(h}some destructive madvise behaviors: MADV_DONTNEED, MADV_FREE, MADV_DONTNEED_LOCKED, MADV_FREE, MADV_DONTFORK, MADV_WIPEONFORKh]h}some destructive madvise behaviors: MADV_DONTNEED, MADV_FREE, MADV_DONTNEED_LOCKED, MADV_FREE, MADV_DONTFORK, MADV_WIPEONFORK}(hjXhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK^hjTubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1j hhhKZhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK_hjubah}(h]h ]h"]h$]h&]uh1jhjubh)}(hXThe first set of syscalls to block is munmap, mremap, mmap. They can either leave an empty space in the address space, therefore allowing replacement with a new mapping with new set of attributes, or can overwrite the existing mapping with another mapping.h]hXThe first set of syscalls to block is munmap, mremap, mmap. They can either leave an empty space in the address space, therefore allowing replacement with a new mapping with new set of attributes, or can overwrite the existing mapping with another mapping.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKahjubh)}(hemprotect and pkey_mprotect are blocked because they changes the protection bits (RWX) of the mapping.h]hemprotect and pkey_mprotect are blocked because they changes the protection bits (RWX) of the mapping.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKfhjubh)}(hXCertain destructive madvise behaviors, specifically MADV_DONTNEED, MADV_FREE, MADV_DONTNEED_LOCKED, and MADV_WIPEONFORK, can introduce risks when applied to anonymous memory by threads lacking write permissions. Consequently, these operations are prohibited under such conditions. The aforementioned behaviors have the potential to modify region contents by discarding pages, effectively performing a memset(0) operation on the anonymous memory.h]hXCertain destructive madvise behaviors, specifically MADV_DONTNEED, MADV_FREE, MADV_DONTNEED_LOCKED, and MADV_WIPEONFORK, can introduce risks when applied to anonymous memory by threads lacking write permissions. Consequently, these operations are prohibited under such conditions. The aforementioned behaviors have the potential to modify region contents by discarding pages, effectively performing a memset(0) operation on the anonymous memory.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKihjubh)}(h/Kernel will return -EPERM for blocked syscalls.h]h/Kernel will return -EPERM for blocked syscalls.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKqhjubh)}(hWhen blocked syscall return -EPERM due to sealing, the memory regions may or may not be changed, depends on the syscall being blocked:h]hWhen blocked syscall return -EPERM due to sealing, the memory regions may or may not be changed, depends on the syscall being blocked:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKshjubjn)}(hXS- munmap: munmap is atomic. If one of VMAs in the given range is sealed, none of VMAs are updated. - mprotect, pkey_mprotect, madvise: partial update might happen, e.g. when mprotect over multiple VMAs, mprotect might update the beginning VMAs before reaching the sealed VMA and return -EPERM. - mmap and mremap: undefined behavior. h]j )}(hhh](j)}(h`munmap: munmap is atomic. If one of VMAs in the given range is sealed, none of VMAs are updated.h]h)}(h`munmap: munmap is atomic. If one of VMAs in the given range is sealed, none of VMAs are updated.h]h`munmap: munmap is atomic. If one of VMAs in the given range is sealed, none of VMAs are updated.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKvhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hmprotect, pkey_mprotect, madvise: partial update might happen, e.g. when mprotect over multiple VMAs, mprotect might update the beginning VMAs before reaching the sealed VMA and return -EPERM.h]h)}(hmprotect, pkey_mprotect, madvise: partial update might happen, e.g. when mprotect over multiple VMAs, mprotect might update the beginning VMAs before reaching the sealed VMA and return -EPERM.h]hmprotect, pkey_mprotect, madvise: partial update might happen, e.g. when mprotect over multiple VMAs, mprotect might update the beginning VMAs before reaching the sealed VMA and return -EPERM.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKxhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h%mmap and mremap: undefined behavior. h]h)}(h$mmap and mremap: undefined behavior.h]h$mmap and mremap: undefined behavior.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK{hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1j hhhKvhjubah}(h]h ]h"]h$]h&]uh1jmhhhKvhjubeh}(h]h ]h"]h$]h&]uh1jmhhhKNhjhhubeh}(h]%blocked-mm-syscall-for-sealed-mappingah ]h"]%blocked mm syscall for sealed mappingah$]h&]uh1hhjKhhhhhKMubeh}(h]syscallah ]h"]syscallah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h Use casesh]h Use cases}(hj>hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj;hhhhhK~ubj )}(hhh](j)}(hbglibc: The dynamic linker, during loading ELF executables, can apply sealing to mapping segments. h]h)}(haglibc: The dynamic linker, during loading ELF executables, can apply sealing to mapping segments.h]haglibc: The dynamic linker, during loading ELF executables, can apply sealing to mapping segments.}(hjShhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjOubah}(h]h ]h"]h$]h&]uh1jhjLhhhhhNubj)}(hAChrome browser: protect some security sensitive data structures. h]h)}(h@Chrome browser: protect some security sensitive data structures.h]h@Chrome browser: protect some security sensitive data structures.}(hjkhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjgubah}(h]h ]h"]h$]h&]uh1jhjLhhhhhNubj)}(hXSystem mappings: The system mappings are created by the kernel and includes vdso, vvar, vvar_vclock, vectors (arm compat-mode), sigpage (arm compat-mode), uprobes. Those system mappings are readonly only or execute only, memory sealing can protect them from ever changing to writable or unmmap/remapped as different attributes. This is useful to mitigate memory corruption issues where a corrupted pointer is passed to a memory management system. If supported by an architecture (CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS), the CONFIG_MSEAL_SYSTEM_MAPPINGS seals all system mappings of this architecture. The following architectures currently support this feature: x86-64, arm64, and s390. WARNING: This feature breaks programs which rely on relocating or unmapping system mappings. Known broken software at the time of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore this config can't be enabled universally. h](h)}(hSystem mappings: The system mappings are created by the kernel and includes vdso, vvar, vvar_vclock, vectors (arm compat-mode), sigpage (arm compat-mode), uprobes.h]hSystem mappings: The system mappings are created by the kernel and includes vdso, vvar, vvar_vclock, vectors (arm compat-mode), sigpage (arm compat-mode), uprobes.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hXThose system mappings are readonly only or execute only, memory sealing can protect them from ever changing to writable or unmmap/remapped as different attributes. This is useful to mitigate memory corruption issues where a corrupted pointer is passed to a memory management system.h]hXThose system mappings are readonly only or execute only, memory sealing can protect them from ever changing to writable or unmmap/remapped as different attributes. This is useful to mitigate memory corruption issues where a corrupted pointer is passed to a memory management system.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hIf supported by an architecture (CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS), the CONFIG_MSEAL_SYSTEM_MAPPINGS seals all system mappings of this architecture.h]hIf supported by an architecture (CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS), the CONFIG_MSEAL_SYSTEM_MAPPINGS seals all system mappings of this architecture.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hTThe following architectures currently support this feature: x86-64, arm64, and s390.h]hTThe following architectures currently support this feature: x86-64, arm64, and s390.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hWARNING: This feature breaks programs which rely on relocating or unmapping system mappings. Known broken software at the time of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore this config can't be enabled universally.h]hWARNING: This feature breaks programs which rely on relocating or unmapping system mappings. Known broken software at the time of writing includes CHECKPOINT_RESTORE, UML, gVisor, rr. Therefore this config can’t be enabled universally.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1jhjLhhhhhNubeh}(h]h ]h"]h$]h&]jjuh1j hhhKhj;hhubeh}(h] use-casesah ]h"] use casesah$]h&]uh1hhhhhhhhK~ubh)}(hhh](h)}(hWhen not to use msealh]hWhen not to use mseal}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(hX"Applications can apply sealing to any virtual memory region from userspace, but it is *crucial to thoroughly analyze the mapping's lifetime* prior to apply the sealing. This is because the sealed mapping *won’t be unmapped* until the process terminates or the exec system call is invoked.h](hVApplications can apply sealing to any virtual memory region from userspace, but it is }(hjhhhNhNubhemphasis)}(h6*crucial to thoroughly analyze the mapping's lifetime*h]h6crucial to thoroughly analyze the mapping’s lifetime}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh@ prior to apply the sealing. This is because the sealed mapping }(hjhhhNhNubj)}(h*won’t be unmapped*h]hwon’t be unmapped}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhA until the process terminates or the exec system call is invoked.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hhh]j)}(hXFor example: - aio/shm aio/shm can call mmap and munmap on behalf of userspace, e.g. ksys_shmdt() in shm.c. The lifetimes of those mapping are not tied to the lifetime of the process. If those memories are sealed from userspace, then munmap will fail, causing leaks in VMA address space during the lifetime of the process. - ptr allocated by malloc (heap) Don't use mseal on the memory ptr return from malloc(). malloc() is implemented by allocator, e.g. by glibc. Heap manager might allocate a ptr from brk or mapping created by mmap. If an app calls mseal on a ptr returned from malloc(), this can affect the heap manager's ability to manage the mappings; the outcome is non-deterministic. Example:: ptr = malloc(size); /* don't call mseal on ptr return from malloc. */ mseal(ptr, size); /* free will success, allocator can't shrink heap lower than ptr */ free(ptr); h](j)}(h For example:h]h For example:}(hj) hhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhKhj% ubj)}(hhh]j )}(hhh](j)}(hX5aio/shm aio/shm can call mmap and munmap on behalf of userspace, e.g. ksys_shmdt() in shm.c. The lifetimes of those mapping are not tied to the lifetime of the process. If those memories are sealed from userspace, then munmap will fail, causing leaks in VMA address space during the lifetime of the process. h]h)}(hX4aio/shm aio/shm can call mmap and munmap on behalf of userspace, e.g. ksys_shmdt() in shm.c. The lifetimes of those mapping are not tied to the lifetime of the process. If those memories are sealed from userspace, then munmap will fail, causing leaks in VMA address space during the lifetime of the process.h]hX4aio/shm aio/shm can call mmap and munmap on behalf of userspace, e.g. ksys_shmdt() in shm.c. The lifetimes of those mapping are not tied to the lifetime of the process. If those memories are sealed from userspace, then munmap will fail, causing leaks in VMA address space during the lifetime of the process.}(hjA hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj= ubah}(h]h ]h"]h$]h&]uh1jhj: ubj)}(hX1ptr allocated by malloc (heap) Don't use mseal on the memory ptr return from malloc(). malloc() is implemented by allocator, e.g. by glibc. Heap manager might allocate a ptr from brk or mapping created by mmap. If an app calls mseal on a ptr returned from malloc(), this can affect the heap manager's ability to manage the mappings; the outcome is non-deterministic. Example:: ptr = malloc(size); /* don't call mseal on ptr return from malloc. */ mseal(ptr, size); /* free will success, allocator can't shrink heap lower than ptr */ free(ptr); h](h)}(hXnptr allocated by malloc (heap) Don't use mseal on the memory ptr return from malloc(). malloc() is implemented by allocator, e.g. by glibc. Heap manager might allocate a ptr from brk or mapping created by mmap. If an app calls mseal on a ptr returned from malloc(), this can affect the heap manager's ability to manage the mappings; the outcome is non-deterministic.h]hXrptr allocated by malloc (heap) Don’t use mseal on the memory ptr return from malloc(). malloc() is implemented by allocator, e.g. by glibc. Heap manager might allocate a ptr from brk or mapping created by mmap. If an app calls mseal on a ptr returned from malloc(), this can affect the heap manager’s ability to manage the mappings; the outcome is non-deterministic.}(hjY hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjU ubh)}(h Example::h]hExample:}(hjg hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjU ubj)}(hptr = malloc(size); /* don't call mseal on ptr return from malloc. */ mseal(ptr, size); /* free will success, allocator can't shrink heap lower than ptr */ free(ptr);h]hptr = malloc(size); /* don't call mseal on ptr return from malloc. */ mseal(ptr, size); /* free will success, allocator can't shrink heap lower than ptr */ free(ptr);}hju sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjU ubeh}(h]h ]h"]h$]h&]uh1jhj: ubeh}(h]h ]h"]h$]h&]jjuh1j hhhKhj7 ubah}(h]h ]h"]h$]h&]uh1jhj% ubeh}(h]h ]h"]h$]h&]uh1jhhhKhj" ubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubeh}(h]when-not-to-use-msealah ]h"]when not to use msealah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hmseal doesn't blockh]hmseal doesn’t block}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hhhhhKubh)}(hIn a nutshell, mseal blocks certain mm syscall from modifying some of VMA's attributes, such as protection bits (RWX). Sealed mappings doesn't mean the memory is immutable.h]hIn a nutshell, mseal blocks certain mm syscall from modifying some of VMA’s attributes, such as protection bits (RWX). Sealed mappings doesn’t mean the memory is immutable.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubh)}(hAs Jann Horn pointed out in [3], there are still a few ways to write to RO memory, which is, in a way, by design. And those could be blocked by different security measures.h]hAs Jann Horn pointed out in [3], there are still a few ways to write to RO memory, which is, in a way, by design. And those could be blocked by different security measures.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubh)}(hThose cases are:h]hThose cases are:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubjn)}(h- Write to read-only memory through /proc/self/mem interface (FOLL_FORCE). - Write to read-only memory through ptrace (such as PTRACE_POKETEXT). - userfaultfd. h]j )}(hhh](j)}(hHWrite to read-only memory through /proc/self/mem interface (FOLL_FORCE).h]h)}(hj h]hHWrite to read-only memory through /proc/self/mem interface (FOLL_FORCE).}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(hCWrite to read-only memory through ptrace (such as PTRACE_POKETEXT).h]h)}(hj h]hCWrite to read-only memory through ptrace (such as PTRACE_POKETEXT).}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h userfaultfd. h]h)}(h userfaultfd.h]h userfaultfd.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]jjuh1j hhhKhj ubah}(h]h ]h"]h$]h&]uh1jmhhhKhj hhubh)}(hThe idea that inspired this patch comes from Stephen Röttger’s work in V8 CFI [4]. Chrome browser in ChromeOS will be the first user of this API.h]hThe idea that inspired this patch comes from Stephen Röttger’s work in V8 CFI [4]. Chrome browser in ChromeOS will be the first user of this API.}(hj= hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubeh}(h]mseal-doesn-t-blockah ]h"]mseal doesn't blockah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h Referenceh]h Reference}(hjV hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjS hhhhhKubj )}(hhh](j)}(h[1] https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/mach/vm_statistics.h#L274h]h)}(hji h](h[1] }(hjk hhhNhNubh)}(h|https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/mach/vm_statistics.h#L274h]h|https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/mach/vm_statistics.h#L274}(hjr hhhNhNubah}(h]h ]h"]h$]h&]refurijt uh1hhjk ubeh}(h]h ]h"]h$]h&]uh1hhhhKhjg ubah}(h]h ]h"]h$]h&]uh1jhjd hhhhhNubj)}(h([2] https://man.openbsd.org/mimmutable.2h]h)}(hj h](h[2] }(hj hhhNhNubh)}(h$https://man.openbsd.org/mimmutable.2h]h$https://man.openbsd.org/mimmutable.2}(hj hhhNhNubah}(h]h ]h"]h$]h&]refurij uh1hhj ubeh}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhjd hhhhhNubj)}(hc[3] https://lore.kernel.org/lkml/CAG48ez3ShUYey+ZAFsU2i1RpQn0a5eOs2hzQ426FkcgnfUGLvA@mail.gmail.comh]h)}(hj h](h[3] }(hj hhhNhNubh)}(h_https://lore.kernel.org/lkml/CAG48ez3ShUYey+ZAFsU2i1RpQn0a5eOs2hzQ426FkcgnfUGLvA@mail.gmail.comh]h_https://lore.kernel.org/lkml/CAG48ez3ShUYey+ZAFsU2i1RpQn0a5eOs2hzQ426FkcgnfUGLvA@mail.gmail.com}(hj hhhNhNubah}(h]h ]h"]h$]h&]refurij uh1hhj ubeh}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhjd hhhhhNubj)}(ho[4] https://docs.google.com/document/d/1O2jwK4dxI3nRcOJuPYkonhTkNQfbmwdvxQMyXgeaRHo/edit#heading=h.bvaojj9fu6hch]h)}(hj h](h[4] }(hj hhhNhNubh)}(hkhttps://docs.google.com/document/d/1O2jwK4dxI3nRcOJuPYkonhTkNQfbmwdvxQMyXgeaRHo/edit#heading=h.bvaojj9fu6hch]hkhttps://docs.google.com/document/d/1O2jwK4dxI3nRcOJuPYkonhTkNQfbmwdvxQMyXgeaRHo/edit#heading=h.bvaojj9fu6hc}(hj hhhNhNubah}(h]h ]h"]h$]h&]refurij uh1hhj ubeh}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhjd hhhhhNubeh}(h]h ]h"]h$]h&]jjuh1j hhhKhjS hhubeh}(h] referenceah ]h"] referenceah$]h&]uh1hhhhhhhhKubeh}(h]introduction-of-msealah ]h"]introduction of msealah$]h&]uh1hhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerj8 error_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(j j j8j5jjj0j-jjj j jP jM j j u nametypes}(j j8jj0jj jP j uh}(j hj5jKjj\j-jjj;j jjM j j jS u footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}Rparse_messages]transform_messages] transformerN include_log] decorationNhhub.