Grsecurity/How to Contribute

Grsecurity
Terminology How to Contribute Obtaining grsecurity


The easiest way to contribute is to enhance existing content by correcting misspelled words or restructuring sentences or paragraphs to make them more readable. You are also very welcome to add new content by expanding pages that are under development or by adding completely new pages if your text doesn't fit any of the other pages. As grsecurity is being actively developed and features are added and removed, help with keeping the content up to date is much appreciated.

On this page you will find background on why a particular structure was chosen for the book, who this book is for, and what style and formatting should be used.

Book Structure

edit

The book's structure follows the original documentation of the grsecurity project that had three main chapters: Installation, Configuration and Specification, and Using gradm and the Learning Mode. Configuration and Specification was retitled as Policy Configuration. Using gradm and the Learning Mode was retitled as Administration and was also moved before the Policy Configuration, because you must know how to manage grsecurity before you configure the policy. This is how we ended up with the core structure: Installation, Administration, Policy Configuration.

Target Audience

edit

The book is meant for people who are capable of solving hardware and software problems of varying complexity on their own and who actually read the manual. They know their way around their favorite Linux distribution and are familiar with configuring and building software from source.

Objectives

edit

The purpose of this book is to provide comprehensive, reliable, and up-to-date documentation of grsecurity and related tools. In addition to teaching how to do something, the book provides information about best practices and common pitfalls learned in practice. This is the main objective.

Each chapter has additional objectives that define what the reader should know after they've read it. These objectives were defined after most of the book's core content was in place, so at the time of writing some chapters might not fulfill all of their objectives.

Introduction - The reader must learn on a basic level what grsecurity is, what are its goals and how those goals are realized. If they do not belong to our target audience they should still get a rough idea of what grsecurity is about.

Installation - The reader must learn:

  • Where to get grsecurity, its administration tool gradm and the Linux kernel source.
  • How to verify the authenticity of each package.
  • How to apply the grsecurity patch properly.
  • How to configure grsecurity's kernel configuration options (this includes PaX settings) and what they need to consider before doing so.
  • How to build and install a grsecurity-enabled kernel using their chosen distribution's tools.

Administration - The reader must learn:

  • How to install gradm, the administration tool.
  • How to use gradm and especially the learning mode.
  • How to configure grsecurity's features at runtime.
  • What other useful tools are available, where to get them, and how to install and use them.
  • How to troubleshoot application incompatibilities and problems with grsecurity.

Policy Configuration - The reader must learn:

  • What an RBAC system is and is not, what it can provide when properly configured.
  • What makes a secure policy.
  • The policy structure and rules; they must be familiar with every configuration element and their parameters and configuration inheritance.

Reporting Bugs: The reader must learn how to report bugs; what information is required, how to gather it, and where to send the reports.

Style and Conventions

edit
  • Headers should be title cased.
  • Use the <pre> tag to display long commands, example program output, and file contents.
  • Use the XWarning template when you need to point out an important security consideration or a possibly dangerous operation. It is easier to spot than the classic Warning template when scrolling.
  • Use the Info template when you need to point out something that's related to the surrounding text.
  • The name grsecurity should be written in lowercase and without special formatting unless it begins a sentence. This is how it is written on the grsecurity website.

Formatting

edit

Note: This is still a work in progress, and will change in the future. It will be finalized soon.

Italic
Used for file and directory names.
Boldface
Used for occasional emphasis, such as when introducing a new term.
Constant Width
Used in text for program and command names. Blocks of pre-formatted text is used in examples show what commands to execute and what their output should be.

Generating Content Automatically

edit

Some content in this book can be generated automatically from grsecurity's source files. Scripts and programs that do this are listed here. Fixes and improvements to any of the scripts and programs are welcome, as are complete rewrites.

  As this page and the scripts can be modified by anyone, take care to inspect all code before running it.

Grsecurity and PaX Configuration Options and Sysctl Options

edit

Below is a Python script that outputs two files, one with content for the Grsecurity and PaX Configuration Options page and another for the Sysctl Options page.

The script takes an absolute path to the kernel source patched with grsecurity as input, reads the grsecurity/grsec_sysctl.c, security/Kconfig, and grsecurity/Kconfig files, and outputs two files named Grsecurity_and_PaX_Configuration_Options.wiki and Sysctl_Options.wiki. The contents of Grsecurity_and_PaX_Configuration_Options.wiki can copied as they are to the wiki. Sysctl_Options.wiki only contains categorized lists of links that can be shown in the table on the Sysctl Options page. The links in the Sysctl_Options.wiki file point to anchors on the Grsecurity and PaX Configuration Options page, so the contents of these two files are linked.

The script uses Kconfiglib by Ulf Magnusson for reading the Kconfig files.

Feel free to replace the script with a Perl one-liner or a single command line.

#!/usr/bin/env python

import sys
import codecs
import os
import kconfiglib

def get_sysctl_opts(kern_src_dir):
    """
    Returns a dictionary of sysctl variables related to grsecurity.

    Parameters:
    kern_src_dir    (string) Absolute path to a kernel source directory
                    (e.g. /usr/src/linux-3.2.48.)

    The key of each item is the name of a kernel configuration symbol (e.g.
    GRKERNSEC_SYMLINKOWN) and the value is a list of sysctl variable names
    (e.g. [enforce_symlinksifowner, symlinkown_gid]).
    """
    file_name = os.path.join(kern_src_dir, "grsecurity", "grsec_sysctl.c")
    options = {}
    with open(file_name, 'r') as f:
        cur_symbol = None
        for line in f:
            if line.startswith("#ifdef"):
                start = line.find("GRKERNSEC")
                cur_symbol = line[start:].strip()
                options[cur_symbol] = []
            elif line.startswith("#endif"):
                if cur_symbol in options:
                    options[cur_symbol].sort()
                cur_symbol = None

            if cur_symbol is not None and line.find(".procname") >= 0:
                a = line.find('"') + 1 
                b = line.rfind('"')
                sysctl_var = line[a:b].strip()
                options[cur_symbol].append(sysctl_var)

    return options


def get_categorized_sysctl_opts(sysctl_opts):
    """
    Returns a list of lists or tuples.

    Parameters:
    sysctl_opts     (dict) Dictionary of sysctl variables. This would be the
                    return value of get_sysctl_opts().

    Each index in the returned list specifies a category. The categories are
    [0] Audit/logging variables
    [1] Chroot variables
    [2] Network variables
    [3] Misc. variables

    The categorization is based on the name of the sysctl variable, and is
    not entirely accurate. But it's "good enough."

    Each category consists of a list of tuples. The first element of a tuple
    is the name of a kernel configuration symbol (e.g. GRKERNSEC_SYMLINKOWN)
    and the second element is a sysctl variable that is related to that
    symbol. If a symbol is related to more than one sysctl variable, the list
    will contain multiple tuples that have the same first element.
    """
    audit_opts = []
    chroot_opts = []
    net_opts = []
    other_opts = []

    for item in sysctl_opts.iteritems():
        for opt in item[1]:
            if opt.find("audit") >= 0 or opt.find("log") >= 0:
                audit_opts.append((opt,item[0]))
            elif opt.find("chroot") >= 0:
                chroot_opts.append((opt,item[0]))
            elif opt.find("socket") >= 0 or opt.find("ip") >= 0:
                net_opts.append((opt,item[0]))
            else:
                other_opts.append((opt,item[0]))

    audit_opts.sort()
    chroot_opts.sort()
    net_opts.sort()
    other_opts.sort()
    all_opts = [audit_opts, chroot_opts, net_opts, other_opts]

    return all_opts


def write_wikified_sysctl_opts(kern_src_dir, out_file_name):
    """
    Writes a categorized list of sysctl variables wrapped in MediaWiki links
    constructs.

    Parameters:
    kern_src_dir    (string) Absolute path to a kernel source directory
                    (e.g. /usr/src/linux-3.2.48.)

    out_file_name   (string) Path and file name or just the file name of the
                    output file.

    The links point to anchors on the Grsecurity and PaX Configuration Options
    page. The links are written in alphabetical order by the sysctl variable.
    """
    sysctl_opts = get_sysctl_opts(kern_src_dir)
    categorized_opts = get_categorized_sysctl_opts(sysctl_opts)
    kconfig_path = os.path.join(kern_src_dir, "security", "Kconfig")
    conf = kconfiglib.Config(kconfig_path, kern_src_dir)
    link_fmt = "* [[Grsecurity/Appendix/Grsecurity_and_PaX"\
        "_Configuration_Options#{0}|{1}]]\n"

    with codecs.open(out_file_name, 'w', "utf-8") as f:
        f.write("Category: Audit/logging\n")
        for opt in categorized_opts[0]:
            symbol = conf.get_symbol(opt[1])
            prompt = get_prompt(symbol)
            f.write(link_fmt.format(prompt, opt[0]))

        f.write("\nCategory: Chroot\n")
        for opt in categorized_opts[1]:
            symbol = conf.get_symbol(opt[1])
            prompt = get_prompt(symbol)
            f.write(link_fmt.format(prompt, opt[0]))

        f.write("\nCategory: Network\n")
        for opt in categorized_opts[2]:
            symbol = conf.get_symbol(opt[1])
            prompt = get_prompt(symbol)
            f.write(link_fmt.format(prompt, opt[0]))

        f.write("\nCategory: Miscellaneous\n")
        for opt in categorized_opts[3]:
            symbol = conf.get_symbol(opt[1])
            prompt = get_prompt(symbol)
            f.write(link_fmt.format(prompt, opt[0]))


def get_prompt(item):
    """ 
    Return the first prompt text of the specified symbol or choice.

    Parameters:
    item        (Kconfiglib.Symbol or Kconfiglib.Choice) The object whose
                prompt is to be returned.

    Kconfiglib does not expose the prompt(s) of a Symbol or Choice. They have
    to be extracted from the string representation of a Symbol object. This
    function only returns the first prompt. There may be more prompts and
    they may or may not be identical.
    """
    s = str(item)
    prefix = "Prompts:"
    i = s.find(prefix)
    prompt = None
    if i >= 0:
        a = s.find('"', i + len(prefix)) + 1
        b = s.find('"', a)
        prompt = s[a:b]

    return prompt


def write_wikified_item(f, sysctl_opts, item, level):
    """
    Write the given Kconfiglib.Item in the specified file.

    Parameters:
    f               (file) Output file object open for writing.

    sysctl_opts     (dict) Dictionary of sysctl variables. This would be the
                    return value of get_sysctl_opts().

    item            (Kconfiglib.Item) Item that should be formatted.

    level           (integer) Heading level (number of '=' characters before
                    and after a heading). Items are hierarchical and this
                    function will increment the level when it calls itself
                    recursively to process child Items.

    This function wraps certain properties of item and related content from
    sysctl_opts in MediaWiki markup and writes the output to the specified
    file object.

    If item is a Menu, it is formatted as a heading and its child Items
    are iterated and formatted.

    If item is a Choice, its prompt text is formatted as a heading and
    help text as preformatted text.

    If item is a Symbol, its prompt text is formatted as a heading, name as
    teletype text, help text as preformatted text and all related sysctl
    options as intended lines below a sort of heading that's regular
    unformatted text.
    """
    heading_fmt = "\n{0}{1}{0}\n"
    symbol_fmt = "<tt>{0}</tt><br/>\n"
    help_fmt = "<pre>{0}</pre>\n"
    sysctl_vars_heading = "Related sysctl variables:<br/>\n"
    sysctl_var_fmt = ":<tt>kernel.grsecurity.{0}</tt>\n"

    if item.is_menu():
        if level > 1:
            f.write(heading_fmt.format("=" * level, item.get_title()))
        for subitem in item.get_items():
            write_wikified_item(f, sysctl_opts, subitem, level + 1)

    if item.is_choice():
        f.write(heading_fmt.format("=" * level, get_prompt(item)))
        help_text = item.get_help()
        if help_text is not None and len(help_text) > 0:
            f.write(help_fmt.format(help_text.strip()))
        for subitem in item.get_items():
            write_wikified_item(f, sysctl_opts, subitem, level + 1)

    if item.is_symbol():
        name = item.get_name().strip()
        prompt = get_prompt(item)
        help_text = item.get_help()

        if prompt is not None and len(prompt) >= 3:
            f.write(heading_fmt.format("=" * level, prompt))
            f.write(symbol_fmt.format(name))

            if name in sysctl_opts:
                opt_list = sysctl_opts[name]
                if opt_list is not None and len(opt_list) > 0:
                    f.write(sysctl_vars_heading)
                    for opt in sysctl_opts[name]:
                        f.write(sysctl_var_fmt.format(opt))

            if help_text is not None and len(help_text) > 0:
                f.write(help_fmt.format(help_text.strip()))


def write_wikified_kconfig(kern_src_dir, out_file_name):
    """
    Create a MediaWiki-formatted version of the Kconfig file found in
    the kern_src_dir/security/ directory and write the output to the
    given file.

    Parameters:
    kern_src_dir    (string) Absolute path to a kernel source directory
                    (e.g. /usr/src/linux-3.2.48.)

    out_file_name   (string) Path and file name or just the file name of the
                    output file.
    """
    security_kconfig = os.path.join(kern_src_dir, "security", "Kconfig")
    conf = kconfiglib.Config(security_kconfig, kern_src_dir)
    if conf is not None:
        for menu in conf.get_menus():
            if menu.get_title() == "Grsecurity":
                with codecs.open(out_file_name, 'w', "utf-8") as f:
                    sysctl_opts = get_sysctl_opts(kern_src_dir)
                    write_wikified_item(f, sysctl_opts, menu, 1)
                break

# kern_src_dir is expected to be an absolute path to the kernel
# source directory (e.g. /usr/src/linux-3.2.48).
kern_src_dir = sys.argv[1]
if kern_src_dir is not None and len(kern_src_dir) > 0:
    write_wikified_kconfig(kern_src_dir,
        "Grsecurity_and_PaX_Configuration_Options.wiki")
    write_wikified_sysctl_opts(kern_src_dir, "Sysctl_Options.wiki")
Next Page: Obtaining grsecurity | Previous Page: Terminology
Home: Grsecurity