Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/rainbow/permissions
diff options
context:
space:
mode:
Diffstat (limited to 'rainbow/permissions')
-rw-r--r--rainbow/permissions/__init__.py1
-rw-r--r--rainbow/permissions/manifest.txt153
-rw-r--r--rainbow/permissions/permissions.info6
-rw-r--r--rainbow/permissions/permissions.txt67
-rw-r--r--rainbow/permissions/permlist.py94
-rw-r--r--rainbow/permissions/short.txt44
6 files changed, 365 insertions, 0 deletions
diff --git a/rainbow/permissions/__init__.py b/rainbow/permissions/__init__.py
new file mode 100644
index 0000000..2d52afe
--- /dev/null
+++ b/rainbow/permissions/__init__.py
@@ -0,0 +1 @@
+from rainbow.permissions.permlist import PermissionSet
diff --git a/rainbow/permissions/manifest.txt b/rainbow/permissions/manifest.txt
new file mode 100644
index 0000000..cf0ff54
--- /dev/null
+++ b/rainbow/permissions/manifest.txt
@@ -0,0 +1,153 @@
+Verification System Data
+========================
+
+:Author: Michael Stone <michael@laptop.org>, Noah Kantrowitz <noah@laptop.org>
+:Date: August 8, 2007
+
+Our system for update verification manipulates four kinds of data:
+envelopes, keys, credentials, and manifests.
+
+Presently, we intend to use JSON as a transfer encoding because we only need to
+represent tree-structured data and because we want an encoding that is easily
+and safely parseable in pure Python and in other languages.
+
+If we learn that we need a canonical encoding, a more space-efficient encoding,
+or an encoding that can be more efficiently streamed, then we will consider
+alternatives.
+
+
+Envelopes
+---------
+
+Envelopes are tuples of the form
+
+ (version, type, data) :: (Integer, String, Value)
+ ^ ^ ^
+ | | \________ a JSON value in a format governed by (version, type)
+ | \______ a hint about how to interpret the data field that follows.
+ \_________ an opaque version identifier; see below.
+
+The version identifier is intended to specify a minimal dialect that must be
+supported by compliant clients. Backwards-compatible extensions of this dialect
+may be included in an enveloped value without changing the version identifier.
+
+ Note: Noah suggests make the version identifier transparent and declare it to
+ be an integer with a a monotonically increasing value. I'm okay with this,
+ but since we anticipate changing the identifer only when making
+ backwards-incompatible protocol changes, I think it might as well be opaque.
+
+Keys
+----
+
+Keys are envelopes with version 1 and type "key". A key's datum consists of a
+tuple
+
+ (algorithm, fingerprint, key) :: (String, String, String)
+ ^ ^ ^
+ | | \______ an opaque string specifiying the actual key
+ | \______ an opaque string to use to refer to the key
+ \_________ an opaque algorithm identifier;
+
+In practice, we might see a key encoded as:
+ [1, "key", ["rsa", "12508713460986140897", "AE1908579871250981230896109761"]]
+
+
+Credentials
+-----------
+
+A credential is an envelope with version 1 and type "credential". Conceptually,
+its datum consists of a relation whose tuples are signatures of the form:
+
+ (signature-algorithm, key, message, signature)
+
+However, in practice, the message is defined implicitly by context (i.e. as the
+hash of the manifest with which this credential is paired) and we wish to use
+the credential/manifest system to help detect accidental corruption as early as
+possible, including corruption of the manifest.
+
+Therefore, we actually propose to represent the datum of a manifest credential
+as a tuple of
+
+ (hash-alg, sig-alg, expected-hash, key-identifier, signature)
+
+We include the manifest hash as a convenient way to check that the manifest
+was not accidentally damaged in transit (e.g. by a flash corruption bug).
+
+The key fingerprint identifies the key that should be used to verify the
+signature.
+
+The hash-algorithm and signature-algorithm are used to verify the signature
+against the *computed* manifest-hash (not the one cached in the signature
+message).
+
+Finally, the signature itself is opaque.
+
+In actual JSON, we might imagine that such a message would look like:
+
+ [1, "credential", [ ["sha1", "rsa", "DEADBEEF", "123MYKEY", "0PAQU3S1G"],
+ ["whirlpool", "ecc", "123095", "9912KEY", "8567A"] ] ]
+
+
+
+Manifests
+---------
+
+Manifests are the most complicated piece of the system because they have
+different conceptual and transfer-encoded forms.
+
+Conceptually, a manifest's datum is a constraint-set. Implementations of this
+constraint language are free to support checking as many or as few kinds of
+constraint as they wish. Clearly, though, adequate verification of a file-system
+against a manifest depends on both the presence of a constraint set that
+sufficiently constrains the properties of the file-system being checked and a
+correct and complete implementation of a checker for that constraint-set.
+
+This model controls the implementation cost of both the verification machine
+(and the manifest generation tool) while allowing great flexibility in the
+underlying properties being verified and in the degree to which we compromise
+our implementation goals in the face of time pressure.
+
+Details
+~~~~~~~
+
+There are several basic constraints we wish to support. These include
+constraints on file content, file type (normal, hardlink, symlink, device, ...),
+permissions, ownership, and on the contents of directories.
+
+Manifests are envelopes with version 1 and type "manifest". A manifest's datum
+consists of a tuple of a dictionary of optimization hints and a dictionary of
+constraints. Structurally, the datum looks like
+
+ (Hint -> Value, Constraint -> (Query, Result))
+
+Here "hints" are opaque strings that may be given some uninterpreted data as an
+argument (e.g. "invert-filesystem" : true). These are provided because checking
+some of the global constraints may rely on expensive-to-compute structures such
+as an inverted index that maps inodes to the paths that point to them.
+
+The constraint itself dictionary is also made slightly more complicated in the
+name of speed and memory usage. While conceptually, we wish to store a ternary
+relation with columns
+
+ (constraint-algorithm, query, expected-result)
+
+in practice, we expect that there will very few (~5) constraint algorithms and
+very many (~100000) (query, expected-result) pairs. Hence we suggest
+optimizing for this case by grouping the relation's tuples by
+constraint-algorithm, as shown above in the structural description.
+
+A small example of a manifest might be:
+
+ [1, "manifest", [
+ {"invert-filesystem": ["/links"]},
+ {"file-sha1" : [ ["/etc/passwd", "BLAH18AK"],
+ ["/bin/bash", "LA81985ED"]],
+ "permissions" : [ ["/my/secret", 448] ],
+ "same-inode" : [ [["/links/1", "/links/2", "/links/3"], null] ],
+ "dir-contains" : [ ["/", ["bin", "sbin"]] ],
+ "update-excludes": [ ["/security", null] ]
+ }]]
+
+
+
+
diff --git a/rainbow/permissions/permissions.info b/rainbow/permissions/permissions.info
new file mode 100644
index 0000000..654dc17
--- /dev/null
+++ b/rainbow/permissions/permissions.info
@@ -0,0 +1,6 @@
+use-camera
+use-microphone
+lim_nofile 20
+lim_mem 190e6
+lim_nproc 8
+lim_fsize 10e6
diff --git a/rainbow/permissions/permissions.txt b/rainbow/permissions/permissions.txt
new file mode 100644
index 0000000..09d3bfe
--- /dev/null
+++ b/rainbow/permissions/permissions.txt
@@ -0,0 +1,67 @@
+# We will make a new section in activity.info called:
+[Capabilities]
+
+# There are several protections which cannot be modified by the installer.
+# P_BIOS_CORE -- we sign bios with dev key; firmware checks
+# P_BIOS_COPY -- not our problem
+# P_SF_CORE -- may be turned off with dev key.
+# P_SF_RUN -- What, exactly, does "system files" refer to?
+
+net=1 # over-all net access; (1, 0)
+net.limits.burst=10 # token bucket depth; tokens
+net.limits.steady=2 # token bucket refill rate; tokens / sec
+net.limits.connections=5 # connections
+
+# There are several network options that we don't know how or why to implement
+# at the moment
+
+#net.limits.quota=3.5 # total throughput megabytes
+#net.firewall=??? # some firewall rules, TBD
+#net.access_rules.times= #
+#net.ports.53.bind=1 # allow us to bind on port 53
+
+
+nand.limits.burst=1 # tokens
+nand.limits.steady=1 # tokens / sec
+nand.limits.quota=0 # mb
+
+# timed capabilities? (all boolean flags allowing capability request)
+
+microphone=1 # boolean flags
+microphone.analog=0 #
+camera=1 #
+
+
+# -- can these be turned off?
+cpu.limits.burst=100 # tokens
+cpu.limits.steady=50 # tokens/sec
+
+# P_RTC -- is this a configurable flag?
+
+dsp.bg=1 # we want to play sounds in the background
+
+x=0 # synthetic X events
+
+fs.full=0 # we don't need full disk access
+usb=0 # or usb access
+sd=0 # or SD access
+
+# As Noah notes, we're *going* to need an async-notification scheme.
+# That can be spammed, so it needs a permission.
+# Likewise for a search service.
+
+#P_IDENT -- any permissions?
+#P_SANDBOX -- no permissions ATM; eventual fine-grained library & binary inclusion
+
+document=0 # boolean flag
+document.read_only= # mime-type
+document.limits.burst=0 # tokens
+document.limits.steady=0 # tokens/sec
+
+
+#P_DOCUMENT_BACKUP -- no permissions
+#P_THEFT -- no permissions
+#P_SERVER_AUTH -- no permissions... (depends on P_NET?)
+#P_PASSWORD -- no permissions
+
+
diff --git a/rainbow/permissions/permlist.py b/rainbow/permissions/permlist.py
new file mode 100644
index 0000000..897beca
--- /dev/null
+++ b/rainbow/permissions/permlist.py
@@ -0,0 +1,94 @@
+DOMAINS = {'network': ('via', 'to', 'port', 'rate', 'burst', 'connection-rate',
+ 'transfer-limit', 'bind-port'),
+ 'constant-uid': (),
+ 'strace': (),
+ 'use-audio': (),
+ 'use-video': (),
+ 'use-serial': (),
+ 'play-background-sound': (),
+ 'quota': ('limit'),
+ 'lim_nofile': ('@NUM@'),
+ 'lim_mem': ('@NUM@'),
+ 'lim_nproc': ('@NUM@'),
+ 'lim_fsize': ('@NUM@'),
+ 'document_read_ro': ('type')
+ }
+
+class PermissionSet(object):
+ def __init__(self, fp=None):
+ self._permissions = {}
+ self._network_permissions = []
+
+ for line in fp:
+ line = line.lower().strip()
+ if not line or line.startswith('#'):
+ continue
+
+ fields = line.split()
+ if not fields[0] in DOMAINS:
+ print "Unknown permissions domain: [%s]" % fields[0]
+ continue
+
+ for field in fields[1:]:
+ if '@NUM@' in DOMAINS[fields[0]]:
+ try:
+ float(fields[1])
+ except:
+ print "Expecting numeric value in domain [%s] (%s)" % (fields[0], fields[1])
+ continue
+ else:
+ key, value = field.split(':')
+ if not key in DOMAINS[fields[0]]:
+ print "Unknown flag [%s] in domain [%s]" % (key, fields[0])
+ continue
+
+ if fields[0] == 'network':
+ self._network_permissions.append(fields[1:])
+ else:
+ self._permissions[fields[0]] = fields[1:] or True
+
+ def has_permission(self, domain, key=None, value=None):
+ "Fails for network, since it doesn't make sense to query those perms"
+ if domain not in self._permissions:
+ return False
+ elif key and value:
+ for permission in self._permissions[domain]:
+ this_key, these_values = permission.split(':')
+ if not key == this_key:
+ continue
+ these_values = these_values.split(',')
+ if value in these_values:
+ return True
+ return self._permissions[domain] == True
+
+ def permission_params(self, domain):
+ if domain not in self._permissions:
+ return None
+ return(self._permissions[domain])
+
+
+if __name__ == '__main__':
+ import cStringIO as stringio
+ from pprint import pprint
+
+ perms = """
+ network via:ipv4,ipv6 to:pgp.mit.edu,laptop.org port:80 rate:100Kb/s burst:1Mb
+ network via:ipv4 port:25 connection-rate:10/min transfer-limit:8Mb/hr
+ network via:ipv6 bind-port:1400
+
+ # Comment
+ use-microphone
+ use-camera
+
+ # Comment, yay
+ play-background-sound
+
+ document_read_ro type:text/plain
+
+ quota limit:15Mb
+ """
+
+ permfp = stringio.StringIO(perms)
+ permset = PermissionSet(permfp)
+ pprint(permset._permissions)
+ pprint(permset._network_permissions)
diff --git a/rainbow/permissions/short.txt b/rainbow/permissions/short.txt
new file mode 100644
index 0000000..f012220
--- /dev/null
+++ b/rainbow/permissions/short.txt
@@ -0,0 +1,44 @@
+# We will make a new section in activity.info called:
+[Capabilities]
+
+
+net=1 # over-all net access; (1, 0)
+net.limits.burst=10 # token bucket depth; tokens
+net.limits.steady=2 # token bucket refill rate; tokens / sec
+net.limits.connections=5 # connections
+
+#net.limits.quota=3.5 # total throughput megabytes
+#net.firewall=??? # some firewall rules, TBD
+#net.access_rules.times= #
+#net.ports.53.bind=1 # allow us to bind on port 53
+
+nand.limits.burst=1 # tokens
+nand.limits.steady=1 # tokens / sec
+nand.limits.quota=0 # mb
+
+
+microphone=1 # boolean flags
+microphone.analog=0 #
+camera=1 #
+dsp.bg=1 # we want to play sounds in the background
+
+
+cpu.limits.burst=100 # tokens
+cpu.limits.steady=50 # tokens/sec
+
+
+x=0 # synthetic X events
+
+
+fs.full=0 # we don't need full disk access
+usb=0 # or usb access
+sd=0 # or SD access
+
+
+document=0 # boolean flag
+document.read_only= # mime-type
+document.limits.burst=0 # tokens
+document.limits.steady=0 # tokens/sec
+
+
+