wiki/packages/hardened_malloc/index.html

873 lines
27 KiB
HTML

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The wiki for the Rocky Linux Security Special Interest Group">
<link rel="canonical" href="https://sig-security.rocky.page/packages/hardened_malloc/">
<link rel="prev" href="../glibc/">
<link rel="next" href="../lkrg/">
<link rel="icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.11">
<title>Extra package: hardened_malloc - SIG/Security Wiki</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.7e359304.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="teal" data-md-color-accent="teal">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#extra-package-hardened_malloc" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="SIG/Security Wiki" class="md-header__button md-logo" aria-label="SIG/Security Wiki" data-md-component="logo">
<img src="../../assets/icon-white.svg" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
SIG/Security Wiki
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Extra package: hardened_malloc
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="teal" data-md-color-accent="teal" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3 3.19.09m3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95 2.06.05m-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31Z"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="teal" data-md-color-accent="teal" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5c-.84 0-1.65.15-2.39.42L12 2M3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29L3.34 7m.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14L3.36 17M20.65 7l-1.77 3.79a7.023 7.023 0 0 0-2.38-4.15l4.15.36m-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29L20.64 17M12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44L12 22Z"/></svg>
</label>
</form>
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://git.resf.org/security/wiki" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
</div>
<div class="md-source__repository">
security/wiki
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--integrated" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="SIG/Security Wiki" class="md-nav__button md-logo" aria-label="SIG/Security Wiki" data-md-component="logo">
<img src="../../assets/icon-white.svg" alt="logo">
</a>
SIG/Security Wiki
</label>
<div class="md-nav__source">
<a href="https://git.resf.org/security/wiki" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
</div>
<div class="md-source__repository">
security/wiki
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
<span class="md-ellipsis">
SIG/Security Wiki
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../news/" class="md-nav__link">
<span class="md-ellipsis">
News
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_3" >
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="">
<span class="md-ellipsis">
Issues
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Issues
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../issues/CVE-2023-23583/" class="md-nav__link">
<span class="md-ellipsis">
CVE-2023-23583: microcode_ctl
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../issues/CVE-2023-4911/" class="md-nav__link">
<span class="md-ellipsis">
CVE-2023-4911: glibc
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" checked>
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="">
<span class="md-ellipsis">
Packages
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Packages
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../control/" class="md-nav__link">
<span class="md-ellipsis">
Extra package: control
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../glibc/" class="md-nav__link">
<span class="md-ellipsis">
Override package: glibc
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Extra package: hardened_malloc
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Extra package: hardened_malloc
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#el9" class="md-nav__link">
<span class="md-ellipsis">
EL9
</span>
</a>
<nav class="md-nav" aria-label="EL9">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#package-summary" class="md-nav__link">
<span class="md-ellipsis">
Package summary
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#usage-in-rocky-linux" class="md-nav__link">
<span class="md-ellipsis">
Usage in Rocky Linux
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#bugs-uncovered-by-hardened_malloc" class="md-nav__link">
<span class="md-ellipsis">
Bugs uncovered by hardened_malloc
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#potential-for-issues-with-edr" class="md-nav__link">
<span class="md-ellipsis">
Potential for issues with EDR
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#change-log" class="md-nav__link">
<span class="md-ellipsis">
Change log
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../lkrg/" class="md-nav__link">
<span class="md-ellipsis">
Extra package: lkrg
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../microcode_ctl/" class="md-nav__link">
<span class="md-ellipsis">
Override package: microcode_ctl
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../openssh/" class="md-nav__link">
<span class="md-ellipsis">
Override package: openssh
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../passwdqc/" class="md-nav__link">
<span class="md-ellipsis">
Extra package: passwdqc
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<a href="https://git.resf.org/security/wiki/_edit/main/docs/packages/hardened_malloc.md" title="Edit this page" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4v-2m10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1 2.1 2.1Z"/></svg>
</a>
<h1 id="extra-package-hardened_malloc">Extra package: hardened_malloc<a class="headerlink" href="#extra-package-hardened_malloc" title="Permanent link">&para;</a></h1>
<h2 id="el9">EL9<a class="headerlink" href="#el9" title="Permanent link">&para;</a></h2>
<ul>
<li>Version <code>hardened_malloc-12-3.el9_2.security</code></li>
<li>Based on upstream version <code>12</code></li>
<li>No plans to support older Rocky Linux versions due to glibc being too old</li>
</ul>
<h3 id="package-summary">Package summary<a class="headerlink" href="#package-summary" title="Permanent link">&para;</a></h3>
<p>This package ships the "normal" and "light" configurations of the <a href="https://grapheneos.org">GrapheneOS</a> <a href="https://github.com/GrapheneOS/hardened_malloc">hardened_malloc</a> project. The official README.md in the upstream project documents security properties and explains the differences between the regular and light variants.</p>
<h3 id="usage-in-rocky-linux">Usage in Rocky Linux<a class="headerlink" href="#usage-in-rocky-linux" title="Permanent link">&para;</a></h3>
<p>It is strongly reccomended to read all documentation here before deploying this package on your infrastructure.</p>
<p>In order to support the large amount of mappings caused by guard slabs and large allocation guard regions, the <code>vm.max_map_count</code> sysctl is increased as part of package installation to <code>1048576</code> in <code>/etc/sysctl.d/hardened_malloc.conf</code>. You'll need to run <code>sysctl -p /etc/sysctl.d/hardened_malloc.conf</code> for this change to take effect without a reboot. Incidentally, <a href="https://fedoraproject.org/wiki/Changes/IncreaseVmMaxMapCount">Fedora 39 made the same change</a>, so it's not an exotic configuration.</p>
<p>The package ships 2 builds of <code>hardened_malloc</code>, the regular variant, which is located at <code>/usr/lib64/libhardened_malloc.so</code> and can be preloaded using the <code>hardened_malloc_preload.sh</code> script, and the light variant, which is located at <code>/usr/lib64/libhardened_malloc-light.so</code> and can be preloaded using the <code>hardened_malloc_light_preload.sh</code> script. The preload scripts add the relevant library to <code>LD_PRELOAD</code> and then load the desired binary, as shown in the following example: <code>hardened_malloc_preload.sh cat /proc/self/maps</code>.</p>
<p>Users may choose to set an OS-wide <code>LD_PRELOAD</code> with <code>hardened_malloc</code>. This can be done by adding the desired library, for example, <code>/usr/lib64/libhardened_malloc.so</code>, into your <code>/etc/ld.so.preload</code>. Be aware that for applications where <code>AT_SECURE</code> is set, this approach will not work.</p>
<p>It is suggested that if you wish to deploy <code>hardened_malloc</code> systemwide, that you deploy it in your <code>LD_PRELOAD</code> with the normal variant globally, and then for applications which are performance sensitive, or which fail with the normal variant, try them individually with the light variant using the preload script or by setting <code>LD_PRELOAD</code> within a systemd service namespace. If that does not resolve your issue, try disabling <code>hardened_malloc</code> by running the program in its own systemd service namespace.</p>
<h3 id="bugs-uncovered-by-hardened_malloc">Bugs uncovered by hardened_malloc<a class="headerlink" href="#bugs-uncovered-by-hardened_malloc" title="Permanent link">&para;</a></h3>
<p>As with all infrastructure changes, ensure you test in your staging environment extensively before deploying into production. Many packages and projects suffer from memory corruption bugs, which when running under glibc are not encountered during operation, but which <code>hardened_malloc</code> uncovers. Some applications may crash during usage, completely break, or break when running with certain configurations. Bugs in packages are typically a result of upstream project bugs, and should be reported there. In some cases these bugs are fixed in later versions in the upstream project, in which case the bug is an issue with Rocky Linux, and should be reported to Rocky Linux and its upstream distribution, so that the patch may be included.</p>
<table>
<thead>
<tr>
<th>Package name</th>
<th>Latest version tested</th>
<th>Normal variant</th>
<th>Light variant</th>
</tr>
</thead>
<tbody>
<tr>
<td>php</td>
<td>php-8.0.30-1.el9_2.x86_64</td>
<td>Broken</td>
<td>Broken</td>
</tr>
<tr>
<td>php</td>
<td>php-8.1.14-1.module+el9.2.0+15232+36037ab0.x86_64</td>
<td>Broken</td>
<td>Broken</td>
</tr>
<tr>
<td>sssd</td>
<td>sssd-2.8.2-3.el9_2.x86_64</td>
<td>Broken</td>
<td>Broken</td>
</tr>
</tbody>
</table>
<h3 id="potential-for-issues-with-edr">Potential for issues with EDR<a class="headerlink" href="#potential-for-issues-with-edr" title="Permanent link">&para;</a></h3>
<p>By nature of relying on <code>LD_PRELOAD</code>, if you have EDR software on your server, it may falsely send alerts when using <code>hardened_malloc</code>. If it doesn't, your EDR is probably terrible or misconfigured.</p>
<h3 id="change-log">Change log<a class="headerlink" href="#change-log" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code>* Tue Nov 14 2023 Solar Designer &lt;solar@openwall.com&gt; 12-3
- Package hardened_malloc_light_preload.sh
- Disable arm64 building for now (fix didn&#39;t work)
* Wed Nov 8 2023 flawedworld &lt;flawedworld@flawed.world&gt; 12-2
- Set CONFIG_NATIVE to false
- Mark libraries as executable (change to 755 permissions)
- Add hardened_malloc_light_preload.sh
- Fix arm64 building
* Sat Oct 28 2023 flawedworld &lt;flawedworld@flawed.world&gt; 12-1
- Initial packaging for hardened_malloc version 12, co-authored-by
Scott Shinn (atomicturtle) and Solar Designer
</code></pre></div>
<aside class="md-source-file">
<span class="md-source-file__fact">
<span class="md-icon" title="Last update">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1-2.1-2M12.5 7v5.2l4 2.4-1 1L11 13V7h1.5M11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2v1.8Z"/></svg>
</span>
<span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">November 15, 2023</span>
</span>
</aside>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12Z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2023 Rocky Enterprise Software Foundation
</div>
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": ["navigation.expand", "navigation.indexes", "navigation.instant", "navigation.sections", "navigation.top", "navigation.tracking", "navigation.path", "search.highlight", "search.suggest", "toc.integrate", "content.action.edit"], "search": "../../assets/javascripts/workers/search.b8dbb3d2.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
<script src="../../assets/javascripts/bundle.8fd75fb4.min.js"></script>
</body>
</html>