defensive-coding-guide/_package/main/master/en-US/tasks/Tasks-Processes.html
Brian (bex) Exelbierd 2e8934be40 Converted to AsciiBinder
This required moving files around in the repository and shifting
from a master.adoc structure to _topic_map.yml, etc.

README and Makefile modified slightly to reflect new build process
2018-02-08 13:08:40 +01:00

702 lines
No EOL
32 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Defensive Coding Guide | Defensive Coding Guide | Specific Programming Tasks | Processes</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- Overpass Font -->
<link rel="stylesheet" href="https://overpass-30e2.kxcdn.com/overpass.css">
<link href="../../../master/_stylesheets/asciibinder.css" rel="stylesheet" />
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link href="../../../master/_images/favicon32x32.png" rel="shortcut icon" type="text/css">
<!--[if IE]><link rel="shortcut icon" href="../../../master/_images/favicon.ico"><![endif]-->
<meta content="AsciiBinder" name="application-name">
</head>
<body>
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="https://docs.fedoraproject.org/"><img alt="Fedora Documentation" src="../../../master/_images/fedora.svg"></a>
</div>
</div>
</div>
<div class="container">
<p class="toggle-nav visible-xs pull-left">
<button class="btn btn-default btn-sm" type="button" data-toggle="offcanvas">Toggle nav</button>
</p>
<ol class="breadcrumb">
<li class="sitename">
<a href="../../../index.html">Home</a>
</li>
<li class="hidden-xs active">
<a href="../../en-US/index.html">Defensive Coding Guide </a>
</li>
<li class="hidden-xs active">
<a href="../../en-US/index.html">Defensive Coding Guide</a>
</li>
<li class="hidden-xs active"><a href="../../en-US/tasks/Tasks-Library_Design.html">Specific Programming Tasks</a></li>
<li class="hidden-xs active">
Processes
</li>
</ol>
<div class="row row-offcanvas row-offcanvas-left">
<div class="col-xs-8 col-sm-3 col-md-3 sidebar sidebar-offcanvas">
<ul class="nav nav-sidebar">
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicGroup0">
<span id="tgSpan0" class="fa fa-angle-down"></span>Defensive Coding Guide
</a>
<ul id="topicGroup0" class="collapse in list-unstyled">
<li><a class="" href="../../en-US/index.html">Book Information</a></li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-1">
<span id="sgSpan-0-1" class="fa fa-caret-right"></span>&nbsp;Programming Languages
</a>
<ul id="topicSubGroup-0-1" class="nav-tertiary list-unstyled collapse">
<li><a class="" href="../../en-US/programming-languages/C.html">The C Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/CXX.html">The C++ Programming&nbsp;Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Java.html">The Java Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Python.html">The Python Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Shell.html">Shell Programming and bash</a></li>
<li><a class="" href="../../en-US/programming-languages/Go.html">The Go Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Vala.html">The Vala Programming Language</a></li>
</ul>
</li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-2">
<span id="sgSpan-0-2" class="fa fa-caret-down"></span>&nbsp;Specific Programming Tasks
</a>
<ul id="topicSubGroup-0-2" class="nav-tertiary list-unstyled collapse in">
<li><a class="" href="../../en-US/tasks/Tasks-Library_Design.html">Library Design</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Descriptors.html">File Descriptor Management</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-File_System.html">File System Manipulation</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Temporary_Files.html">Temporary Files</a></li>
<li><a class=" active" href="../../en-US/tasks/Tasks-Processes.html">Processes</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Serialization.html">Serialization and Deserialization</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Cryptography.html">Cryptography</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Packaging.html">RPM Packaging</a></li>
</ul>
</li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-3">
<span id="sgSpan-0-3" class="fa fa-caret-right"></span>&nbsp;Implementing Security Features
</a>
<ul id="topicSubGroup-0-3" class="nav-tertiary list-unstyled collapse">
<li><a class="" href="../../en-US/features/Features-Authentication.html">Authentication and Authorization</a></li>
<li><a class="" href="../../en-US/features/Features-TLS.html">Transport Layer Security (TLS)</a></li>
<li><a class="" href="../../en-US/features/Features-HSM.html">Hardware Security Modules and Smart Cards</a></li>
</ul>
</li>
<li><a class="" href="../../en-US/Revision_History.html">Revision History</a></li>
</ul>
</li>
</ul>
</div>
<div class="col-xs-12 col-sm-9 col-md-9 main">
<div class="page-header">
<h2>Processes</h2>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-Processes-Creation"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Processes-Creation"></a>Creating Safe Processes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This section describes how to create new child processes in a
safe manner. In addition to the concerns addressed below, there
is the possibility of file descriptor leaks, see <a href="#sect-Defensive_Coding-Tasks-Descriptors-Child_Processes">[sect-Defensive_Coding-Tasks-Descriptors-Child_Processes]</a>.</p>
</div>
<div class="sect2">
<h3 id="obtaining-the-program-path-and-the-command-line-template"><a class="anchor" href="#obtaining-the-program-path-and-the-command-line-template"></a>Obtaining the Program Path and the Command-line Template</h3>
<div class="paragraph">
<p>The name and path to the program being invoked should be
hard-coded or controlled by a static configuration file stored
at a fixed location (at an file system absolute path). The
same applies to the template for generating the command line.</p>
</div>
<div class="paragraph">
<p>The configured program name should be an absolute path. If it
is a relative path, the contents of the <code>PATH</code>
must be obtained in a secure manner (see <a href="#sect-Defensive_Coding-Tasks-secure_getenv">Accessing Environment Variables</a>).
If the <code>PATH</code> variable is not set or untrusted,
the safe default <code>/bin:/usr/bin</code> must be
used.</p>
</div>
<div class="paragraph">
<p>If too much flexibility is provided here, it may allow
invocation of arbitrary programs without proper authorization.</p>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-Tasks-Processes-execve"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Processes-execve"></a>Bypassing the Shell</h3>
<div class="paragraph">
<p>Child processes should be created without involving the system
shell.</p>
</div>
<div class="paragraph">
<p>For C/C++, <code>system</code> should not be used.
The <code>posix_spawn</code> function can be used
instead, or a combination <code>fork</code> and
<code>execve</code>. (In some cases, it may be
preferable to use <code>vfork</code> or the
Linux-specific <code>clone</code> system call instead
of <code>fork</code>.)</p>
</div>
<div class="paragraph">
<p>In Python, the <code>subprocess</code> module bypasses
the shell by default (when the <code>shell</code>
keyword argument is not set to true).
<code>os.system</code> should not be used.</p>
</div>
<div class="paragraph">
<p>The Java class <code>java.lang.ProcessBuilder</code> can be
used to create subprocesses without interference from the
system shell.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="title">Portability notice</div>
<div class="paragraph">
<p>On Windows, there is no argument vector, only a single
argument string. Each application is responsible for parsing
this string into an argument vector. There is considerable
variance among the quoting style recognized by applications.
Some of them expand shell wildcards, others do not. Extensive
application-specific testing is required to make this secure.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Note that some common applications (notably
<strong class="application">ssh</strong>) unconditionally introduce the
use of a shell, even if invoked directly without a shell. It is
difficult to use these applications in a secure manner. In this
case, untrusted data should be supplied by other means. For
example, standard input could be used, instead of the command
line.</p>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-Tasks-Processes-environ"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Processes-environ"></a>Specifying the Process Environment</h3>
<div class="paragraph">
<p>Child processes should be created with a minimal set of
environment variables. This is absolutely essential if there
is a trust transition involved, either when the parent process
was created, or during the creation of the child process.</p>
</div>
<div class="paragraph">
<p>In C/C++, the environment should be constructed as an array of
strings and passed as the <code>envp</code> argument to
<code>posix_spawn</code> or <code>execve</code>.
The functions <code>setenv</code>,
<code>unsetenv</code> and <code>putenv</code>
should not be used. They are not thread-safe and suffer from
memory leaks.</p>
</div>
<div class="paragraph">
<p>Python programs need to specify a <code>dict</code> for
the the <code>env</code> argument of the
<code>subprocess.Popen</code> constructor.
The Java class <code>java.lang.ProcessBuilder</code>
provides a <code>environment()</code> method,
which returns a map that can be manipulated.</p>
</div>
<div class="paragraph">
<p>The following list provides guidelines for selecting the set
of environment variables passed to the child process.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>PATH</code> should be initialized to
<code>/bin:/usr/bin</code>.</p>
</li>
<li>
<p><code>USER</code> and <code>HOME</code> can be inhereted
from the parent process environment, or they can be
initialized from the <code>pwent</code> structure
for the user.</p>
</li>
<li>
<p>The <code>DISPLAY</code> and <code>XAUTHORITY</code>
variables should be passed to the subprocess if it is an X
program. Note that this will typically not work across trust
boundaries because <code>XAUTHORITY</code> refers to a file
with <code>0600</code> permissions.</p>
</li>
<li>
<p>The location-related environment variables
<code>LANG</code>, <code>LANGUAGE</code>,
<code>LC_ADDRESS</code>, <code>LC_ALL</code>,
<code>LC_COLLATE</code>, <code>LC_CTYPE</code>,
<code>LC_IDENTIFICATION</code>,
<code>LC_MEASUREMENT</code>, <code>LC_MESSAGES</code>,
<code>LC_MONETARY</code>, <code>LC_NAME</code>,
<code>LC_NUMERIC</code>, <code>LC_PAPER</code>,
<code>LC_TELEPHONE</code> and <code>LC_TIME</code>
can be passed to the subprocess if present.</p>
</li>
<li>
<p>The called process may need application-specific
environment variables, for example for passing passwords.
(See <a href="#sect-Defensive_Coding-Tasks-Processes-Command_Line_Visibility">Passing Secrets to Subprocesses</a>.)</p>
</li>
<li>
<p>All other environment variables should be dropped. Names
for new environment variables should not be accepted from
untrusted sources.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="robust-argument-list-processing"><a class="anchor" href="#robust-argument-list-processing"></a>Robust Argument List Processing</h3>
<div class="paragraph">
<p>When invoking a program, it is sometimes necessary to include
data from untrusted sources. Such data should be checked
against embedded <code>NUL</code> characters because the
system APIs will silently truncate argument strings at the first
<code>NUL</code> character.</p>
</div>
<div class="paragraph">
<p>The following recommendations assume that the program being
invoked uses GNU-style option processing using
<code>getopt_long</code>. This convention is widely
used, but it is just that, and individual programs might
interpret a command line in a different way.</p>
</div>
<div class="paragraph">
<p>If the untrusted data has to go into an option, use the
<code>--option-name=VALUE</code> syntax, placing the
option and its value into the same command line argument.
This avoids any potential confusion if the data starts with
<code>-</code>.</p>
</div>
<div class="paragraph">
<p>For positional arguments, terminate the option list with a
single <code class="option">--</code> marker after the last option, and
include the data at the right position. The
<code class="option">--</code> marker terminates option processing, and
the data will not be treated as an option even if it starts
with a dash.</p>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-Tasks-Processes-Command_Line_Visibility"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Processes-Command_Line_Visibility"></a>Passing Secrets to Subprocesses</h3>
<div class="paragraph">
<p>The command line (the name of the program and its argument) of
a running process is traditionally available to all local
users. The called program can overwrite this information, but
only after it has run for a bit of time, during which the
information may have been read by other processes. However,
on Linux, the process environment is restricted to the user
who runs the process. Therefore, if you need a convenient way
to pass a password to a child process, use an environment
variable, and not a command line argument. (See <a href="#sect-Defensive_Coding-Tasks-Processes-environ">Specifying the Process Environment</a>.)</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="title">Portability notice</div>
<div class="paragraph">
<p>On some UNIX-like systems (notably Solaris), environment
variables can be read by any system user, just like command
lines.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If the environment-based approach cannot be used due to
portability concerns, the data can be passed on standard
input. Some programs (notably <strong class="application">gpg</strong>)
use special file descriptors whose numbers are specified on
the command line. Temporary files are an option as well, but
they might give digital forensics access to sensitive data
(such as passphrases) because it is difficult to safely delete
them in all cases.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="handling-child-process-termination"><a class="anchor" href="#handling-child-process-termination"></a>Handling Child Process Termination</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When child processes terminate, the parent process is signalled.
A stub of the terminated processes (a
<strong>zombie</strong>, shown as
<code>&lt;defunct&gt;</code> by
<strong class="application">ps</strong>) is kept around until the status
information is collected (<strong>reaped</strong>) by the
parent process. Over the years, several interfaces for this
have been invented:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The parent process calls <code>wait</code>,
<code>waitpid</code>, <code>waitid</code>,
<code>wait3</code> or <code>wait4</code>,
without specifying a process ID. This will deliver any
matching process ID. This approach is typically used from
within event loops.</p>
</li>
<li>
<p>The parent process calls <code>waitpid</code>,
<code>waitid</code>, or <code>wait4</code>,
with a specific process ID. Only data for the specific
process ID is returned. This is typically used in code
which spawns a single subprocess in a synchronous manner.</p>
</li>
<li>
<p>The parent process installs a handler for the
<code>SIGCHLD</code> signal, using
<code>sigaction</code>, and specifies to the
<code>SA_NOCLDWAIT</code> flag.
This approach could be used by event loops as well.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>None of these approaches can be used to wait for child process
terminated in a completely thread-safe manner. The parent
process might execute an event loop in another thread, which
could pick up the termination signal. This means that libraries
typically cannot make free use of child processes (for example,
to run problematic code with reduced privileges in a separate
address space).</p>
</div>
<div class="paragraph">
<p>At the moment, the parent process should explicitly wait for
termination of the child process using
<code>waitpid</code> or <code>waitid</code>,
and hope that the status is not collected by an event loop
first.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="code-suid-code-code-sgid-code-processes"><a class="anchor" href="#code-suid-code-code-sgid-code-processes"></a><code>SUID</code>/<code>SGID</code> processes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Programs can be marked in the file system to indicate to the
kernel that a trust transition should happen if the program is
run. The <code>SUID</code> file permission bit indicates
that an executable should run with the effective user ID equal
to the owner of the executable file. Similarly, with the
<code>SGID</code> bit, the effective group ID is set to
the group of the executable file.</p>
</div>
<div class="paragraph">
<p>Linux supports <strong>fscaps</strong>, which can grant
additional capabilities to a process in a finer-grained manner.
Additional mechanisms can be provided by loadable security
modules.</p>
</div>
<div class="paragraph">
<p>When such a trust transition has happened, the process runs in a
potentially hostile environment. Additional care is necessary
not to rely on any untrusted information. These concerns also
apply to libraries which can be linked into such processes.</p>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-Tasks-secure_getenv"><a class="anchor" href="#sect-Defensive_Coding-Tasks-secure_getenv"></a>Accessing Environment Variables</h3>
<div class="paragraph">
<p>The following steps are required so that a program does not
accidentally pick up untrusted data from environment
variables.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Compile your C/C++ sources with <code>-D_GNU_SOURCE</code>.
The Autoconf macro <code>AC_GNU_SOURCE</code> ensures this.</p>
</li>
<li>
<p>Check for the presence of the <code>secure_getenv</code>
and <code><em>secure_getenv</code> function. The Autoconf
directive <code>AC_CHECK_FUNCS([</em>secure_getenv secure_getenv])</code>
performs these checks.</p>
</li>
<li>
<p>Arrange for a proper definition of the
<code>secure_getenv</code> function. See <a href="#ex-Defensive_Coding-Tasks-secure_getenv">Obtaining a definition for <code>secure_getenv</code></a>.</p>
</li>
<li>
<p>Use <code>secure_getenv</code> instead of
<code>getenv</code> to obtain the value of critical
environment variables. <code>secure_getenv</code>
will pretend the variable has not bee set if the process
environment is not trusted.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Critical environment variables are debugging flags,
configuration file locations, plug-in and log file locations,
and anything else that might be used to bypass security
restrictions or cause a privileged process to behave in an
unexpected way.</p>
</div>
<div class="paragraph">
<p>Either the <code>secure_getenv</code> function or the
<code>__secure_getenv</code> is available from GNU libc.</p>
</div>
<div id="ex-Defensive_Coding-Tasks-secure_getenv" class="exampleblock">
<div class="title">Example 1. Obtaining a definition for <code>secure_getenv</code></div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold">&lt;stdlib.h&gt;</span>
<span style="color:#579">#ifndef</span> HAVE_SECURE_GETENV
<span style="color:#579"># ifdef</span> HAVE__SECURE_GETENV
<span style="color:#579"># define</span> secure_getenv __secure_getenv
<span style="color:#579"># else</span>
<span style="color:#579"># error</span> neither secure_getenv nor __secure_getenv are available
<span style="color:#579"># endif</span>
<span style="color:#579">#endif</span></code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-Processes-Daemons"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Processes-Daemons"></a>Daemons</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Background processes providing system services
(<strong>daemons</strong>) need to decouple themselves from
the controlling terminal and the parent process environment:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Fork.</p>
</li>
<li>
<p>In the child process, call <code>setsid</code>. The
parent process can simply exit (using
<code>_exit</code>, to avoid running clean-up
actions twice).</p>
</li>
<li>
<p>In the child process, fork again. Processing continues in
the child process. Again, the parent process should just
exit.</p>
</li>
<li>
<p>Replace the descriptors 0, 1, 2 with a descriptor for
<code>/dev/null</code>. Logging should be
redirected to <strong class="application">syslog</strong>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Older instructions for creating daemon processes recommended a
call to <code>umask(0)</code>. This is risky because it
often leads to world-writable files and directories, resulting
in security vulnerabilities such as arbitrary process
termination by untrusted local users, or log file truncation.
If the <strong>umask</strong> needs setting, a restrictive
value such as <code>027</code> or <code>077</code>
is recommended.</p>
</div>
<div class="paragraph">
<p>Other aspects of the process environment may have to changed as
well (environment variables, signal handler disposition).</p>
</div>
<div class="paragraph">
<p>It is increasingly common that server processes do not run as
background processes, but as regular foreground process under a
supervising master process (such as
<strong class="application">systemd</strong>). Server processes should
offer a command line option which disables forking and
replacement of the standard output and standard error streams.
Such an option is also useful for debugging.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="semantics-of-command-line-arguments"><a class="anchor" href="#semantics-of-command-line-arguments"></a>Semantics of Command-line Arguments</h2>
<div class="sectionbody">
<div class="paragraph">
<p>After process creation and option processing, it is up to the
child process to interpret the arguments. Arguments can be
file names, host names, or URLs, and many other things. URLs
can refer to the local network, some server on the Internet,
or to the local file system. Some applications even accept
arbitrary code in arguments (for example,
<strong class="application">python</strong> with the
<code class="option">-c</code> option).</p>
</div>
<div class="paragraph">
<p>Similar concerns apply to environment variables, the contents
of the current directory and its subdirectories.</p>
</div>
<div class="paragraph">
<p>Consequently, careful analysis is required if it is safe to
pass untrusted data to another program.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-Processes-Fork-Parallel"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Processes-Fork-Parallel"></a><code>fork</code> as a Primitive for Parallelism</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A call to <code>fork</code> which is not immediately
followed by a call to <code>execve</code> (perhaps after
rearranging and closing file descriptors) is typically unsafe,
especially from a library which does not control the state of
the entire process. Such use of <code>fork</code>
should be replaced with proper child processes or threads.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="bottom" class="text-muted py-3" >
<div class="foot">
<div class="container">
<div class="row footerlinks">
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">About</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Overview">About Fedora</a></dd>
<dd><a href="https://getfedora.org/en/sponsors">Sponsors</a></dd>
<dd><a href="https://fedoramagazine.org">Fedora Magazine</a></dd>
<dd><a href="https://fedoraproject.org/wiki/Legal:Main#Legal">Legal</a></dd>
</dl>
<ul class="list-inline">
<li>
<a href="https://www.facebook.com/TheFedoraProject" class="btn-social btn-outline"><i class="fa fa-fw fa-facebook"></i></a>
</li>
<li>
<a href="https://plus.google.com/112917221531140868607" class="btn-social btn-outline"><i class="fa fa-fw fa-google-plus"></i></a>
</li>
<li>
<a href="https://twitter.com/fedora" class="btn-social btn-outline"><i class="fa fa-fw fa-twitter"></i></a>
</li>
</ul>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title uppercase">Download</h3>
<div class="widget-body">
<dl>
<dd><a href="https://getfedora.org/en/workstation/download">Get Fedora Workstation</a></dd>
<dd><a href="https://getfedora.org/en/server/download">Get Fedora Server</a></dd>
<dd><a href="https://getfedora.org/en/atomic/download">Get Fedora Atomic</a></dd>
<dd><a href="https://spins.fedoraproject.org">Fedora Spins</a></dd>
<dd><a href="https://labs.fedoraproject.org">Fedora Labs</a></dd>
<dd><a href="https://arm.fedoraproject.org">Fedora ARM<span class="sup">&reg;</span></a></dd>
<dd><a href="https://alt.fedoraproject.org/">Alternative Downloads</a></dd>
</dl>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">Support</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Communicating_and_getting_help">Get Help</a></dd>
<dd><a href="https://ask.fedoraproject.org/">Ask Fedora</a></dd>
<dd><a href="https://fedoraproject.org/wiki/Common_F27_bugs">Common Bugs</a></dd>
<dd><a href="https://developer.fedoraproject.org/">Fedora Developer Portal</a></dd>
<dd><a href="https://docs.fedoraproject.org/f27/install-guide/index.html">Installation Guide</a></dd>
</dl>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">Join</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Join">Join Fedora</a></dd>
<dd><a href="http://fedoraplanet.org">Planet Fedora</a></dd>
<dd><a href="https://fedoraproject.org/wiki/SIGs">Fedora SIGs</a></dd>
<dd><a href="https://admin.fedoraproject.org/accounts/">Fedora Account System</a></dd>
<dd><a href="https://fedoracommunity.org/">Fedora Community</a></dd>
</dl>
</div>
</div>
</div> <!-- /row of widgets -->
<div class="row">
<div class="col-md-2">
<div class="widget-body">
<a href="https://www.redhat.com/"><img class="rh-logo" src="../../../master/_images/redhat-logo.png" alt="Red Hat Logo" /></a>
</div>
</div>
<div class="col-md-7">
<div class="widget-body">
<p class="sponsor">Fedora is sponsored by Red Hat.</p>
<p class="sponsor"><a href="https://www.redhat.com/en/technologies/linux-platforms/articles/relationship-between-fedora-and-rhel">Learn more about the relationship between Red Hat and Fedora &raquo;</a></p>
<p class="copy">&copy; 2017 Red Hat, Inc. and others. Please send any comments or corrections to the <a href="https://pagure.io/fedora-docs/docs-fp-o">documentation team</a></p>
</div>
</div>
</div> <!-- /row of widgets -->
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="../../../master/_javascripts/bootstrap-offcanvas.js" type="text/javascript"></script>
<script type="text/javascript">
/*<![CDATA[*/
$(document).ready(function() {
$("[id^='topicGroup']").on('show.bs.collapse', function (event) {
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
}
});
$("[id^='topicGroup']").on('hide.bs.collapse', function (event) {
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
}
});
$("[id^='topicSubGroup']").on('show.bs.collapse', function () {
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
});
$("[id^='topicSubGroup']").on('hide.bs.collapse', function () {
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
});
});
/*]]>*/
</script>
</body>
</html>