Skip to content
academia.sh

Lesson 02 / 11

Operating System Families

Operating system families told apart by their security model rather than their product name: 14 system requests giving a different result across three families in 4, 11, and 12 items, crossing the admin boundary costing 1, 2, and 3 items, the requests reached once the boundary falls being 13, 9, and 5, and the requests unreachable even as admin rising to 1, 1, and 9.

Published Updated

In this lesson

  • Distinguishes operating system families by the security model they carry rather than their product name
  • Counts how many items apart the same set of access requests gives a different result across three families
  • Writes the cost of the admin boundary with two numbers: the items required to cross it and the requests opened once it falls
Contents

The previous lesson counted the boundaries hardware draws and left one distinction open: a hardware boundary only makes possible. The processor offers privilege mode but does not decide which code runs in it; persistent storage stores the permission bits, and whether to honor them is the job of the software that mounts the disk. The layer that makes the decision is the operating system.

When this layer is invoked, product names are usually listed off. A product name carries no decision: names change, versions borrow one another’s features, and two installations under the same name can behave completely differently. What carries the decision is the family’s security model — the response it gives to the same request, and how many items it costs to change that response.

Three Families, Three Models

In this lesson, families are referred to by their model.

The family with discrete user and group permissions. Every object has an owner and a group; access is determined by the bits given to the owner–group–others classes. Privilege is concentrated in a single supreme identity: whoever holds that identity can do everything.

The family with access control lists. An entry is kept per object, per subject; system privileges are also split — changing the clock, taking a full-disk-read backup, touching the log are items that can be granted separately. Being an admin does not automatically grant all of these.

The family based on a signed app store. Executable code comes only from a signed source, and every application runs in its own isolated area. Some requests, even if the user is an admin, are never granted by any means in the model.

What the three definitions share is that all of them can run on the same hardware. The eight boundaries from the previous lesson sit in the same place across all three families; what changes is which request passes under which condition, on top of those boundaries. This is why families can only be compared over the same request set: a comparison made with different request lists measures the difference between the lists, not between the families.

The Same Request Set Across Three Families

The example is the field teams’ laptop in the fictional regional measurement network. The team and the request set are fictional; the matrix below is a model — there is no real distribution, product, or vendor.

HO7: the request set is 14 items and is asked the same way across the three families. HO8: the result takes four values — grant is given directly, admin is given by crossing the admin boundary, separate is given with its own privilege item without becoming full admin, deny is never given in that family, by any means. HO9: crossing the admin boundary requires 1 item in the discrete-permission family, 2 in the access-list family, 3 in the signed-store family. HO10: every separate-result request additionally requires its own item. HO11: the scenario has two stages — first a standard account is compromised, then the admin boundary falls.

// it/family.mjs — the same set of system requests across three operating system families
// (model): not a real distribution, product, or vendor. No randomness.

// Families are named by their security model. cross: items needed to cross the admin
// boundary; extraItem: items needed on top, for each "separate"-result request.
export const FAMILY = [
  { code: "discrete-permission", cross: 1, extraItem: 0 }, // family with discrete user and group permissions
  { code: "access-list", cross: 2, extraItem: 1 },          // family with access control lists
  { code: "signed-store", cross: 3, extraItem: 1 },         // family based on a signed app store
];

// Result: grant (directly), admin (by crossing the admin boundary), separate (with its own
// privilege item, without full admin), deny (never granted in this family).
export const REQUEST = `
  read-own-document               grant  grant     grant
  other-users-document              deny   deny      deny
  write-system-directory           admin  admin      deny
  install-software-from-store      admin  admin     grant
  run-unsigned-software            grant  grant      deny
  load-driver                      admin  admin      deny
  add-startup-item                 grant  grant     admin
  open-privileged-port             admin  admin      deny
  read-another-process-memory      admin  admin      deny
  change-system-clock              admin  separate    deny
  delete-log                       admin  separate    deny
  mount-disk-volume                admin  separate   admin
  camera-and-microphone            grant  grant     admin
  full-disk-read-backup            admin  separate    deny`
  .trim().split("\n").map((r) => {
    const [name, ...s] = r.trim().split(/\s+/);
    return { name, s: Object.fromEntries(FAMILY.map((f, i) => [f.code, s[i]])) };
  });

export const RESULT = ["grant", "admin", "separate", "deny"];
export const count = (f, c) => REQUEST.filter((i) => i.s[f.code] === c).length;

// Two-stage scenario: a standard account is compromised first, then the admin boundary falls.
export function stage(f) {
  const grant = count(f, "grant");
  const admin = count(f, "admin");
  const separate = count(f, "separate");
  return { grant, boundaryFalls: grant + admin, all: grant + admin + separate, cross: f.cross,
    items: f.cross + separate * f.extraItem, deny: count(f, "deny") };
}
// it/familymeasure.mjs — how many items the same request set diverges across three families, and what opens once the boundary falls.
import { FAMILY, REQUEST, RESULT, count, stage } from "./family.mjs";

const write = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const K = FAMILY.map((f) => f.code);

console.log(`${REQUEST.length} system requests x ${FAMILY.length} families; result: ` +
  "grant directly, admin by crossing the admin boundary, separate with its own item, deny never");

const A = [-36, 21, 16, 14];
console.log("\n1. the same request set across three families");
write(A, "request", ...K);
for (const i of REQUEST) write(A, i.name, ...K.map((k) => i.s[k]));

const B = [-36, 21, 16, 14];
console.log("\n2. count per family");
write(B, "measure", ...K);
for (const c of RESULT) write(B, `${c}-result requests`, ...FAMILY.map((f) => count(f, c)));
const R = FAMILY.map(stage);
for (const [name, f] of [["crossing the admin boundary: items", (r) => r.cross],
  ["reaching everything: items", (r) => r.items],
  ["reached with a standard account", (r) => r.grant],
  ["reached once the boundary falls", (r) => r.boundaryFalls],
  ["reached if every item is taken", (r) => r.all],
  ["unreachable even as admin", (r) => r.deny]]) write(B, name, ...R.map(f));

const C = [-36, 21];
console.log("\n3. pairwise comparison (requests with a different result)");
write(C, "pair", "different requests");
for (let x = 0; x < K.length; x++)
  for (let y = x + 1; y < K.length; y++)
    write(C, `${K[x]} - ${K[y]}`,
      REQUEST.filter((i) => i.s[K[x]] !== i.s[K[y]]).length);
write(C, "same across all three", REQUEST.filter((i) => new Set(K.map((k) => i.s[k])).size === 1).length);
write(C, "different across all three", REQUEST.filter((i) => new Set(K.map((k) => i.s[k])).size === 3).length);
14 system requests x 3 families; result: grant directly, admin by crossing the admin boundary, separate with its own item, deny never

1. the same request set across three families
request                               discrete-permission     access-list  signed-store
read-own-document                                   grant           grant         grant
other-users-document                                 deny            deny          deny
write-system-directory                              admin           admin          deny
install-software-from-store                         admin           admin         grant
run-unsigned-software                               grant           grant          deny
load-driver                                         admin           admin          deny
add-startup-item                                    grant           grant         admin
open-privileged-port                                admin           admin          deny
read-another-process-memory                         admin           admin          deny
change-system-clock                                 admin        separate          deny
delete-log                                          admin        separate          deny
mount-disk-volume                                   admin        separate         admin
camera-and-microphone                               grant           grant         admin
full-disk-read-backup                               admin        separate          deny

2. count per family
measure                               discrete-permission     access-list  signed-store
grant-result requests                                   4               4             2
admin-result requests                                   9               5             3
separate-result requests                                0               4             0
deny-result requests                                    1               1             9
crossing the admin boundary: items                      1               2             3
reaching everything: items                              1               6             3
reached with a standard account                         4               4             2
reached once the boundary falls                        13               9             5
reached if every item is taken                         13              13             5
unreachable even as admin                               1               1             9

3. pairwise comparison (requests with a different result)
pair                                   different requests
discrete-permission - access-list                       4
discrete-permission - signed-store                     11
access-list - signed-store                             12
same across all three                                   2
different across all three                              3

The numbers belong to the measurement class; their inputs are HO7–HO11.

How Many Items Is the Admin Boundary

The fifth and sixth rows of the second table give this lesson’s measure. Crossing the admin boundary is 1 item in the discrete-permission family, 2 in the access-list family, 3 in the signed-store family. But the row below is different: the items required to reach every request are 1, 6, and 3.

The difference comes from the splitting of privilege. In the discrete-permission family, crossing to the supreme identity is one item, and that item grants everything; the cost of crossing the boundary and the cost of reaching everything are the same number. In the access-list family, becoming admin does not additionally grant four requests; each of them requires its own privilege item, and the total rises to 6. Split privilege does not raise the height of the boundary — it lengthens the distance beyond it.

Seeing this distinction requires the two numbers to be written separately. The single question “is becoming admin hard” gives the sequence 1, 2, 3 and makes the three families look nearly equal; once the second number is added, the sequence becomes 1, 6, 3, and the ranking changes.

What Opens When the Boundary Falls

The third column group reads the scenario’s second stage. When a standard account is compromised, the requests reached directly are 4, 4, and 2 across the three families — nearly the same. When the admin boundary falls, the numbers diverge: 13, 9, and 5.

In the discrete-permission family, 13 of 14 requests open. A single item grants nearly the entire inventory; this is the software-side counterpart of the pattern seen in the firmware row in the previous lesson. In the access-list family, the requests that open at the same time are 9, and the remaining 4 requests each need one more separate item. In the signed-store family, even when the boundary falls, the requests opened stay at 5, because the remaining 9 requests open with no item at all, in this model.

The last row writes this directly: the number of requests unreachable even as admin is 1, 1, and 9. This is the sharpest difference among the three families, and it comes from a single design decision — whether the highest point of privilege grants everything or not.

The scenario’s second stage is an account’s authority turning into more than the system permits; this step is called privilege escalation. What is measured here is not how the escalation is carried out but the number of requests that open once it is assumed to have happened; the step itself is a model, and this lesson contains no working example of it. Attempting escalation on a system, without written authorization and a defined scope, is both illegal and unprofessional.

The Item the Model Does Not See

The deny value in the table is absolute in the model: that request opens with no item at all. In a real installation it is not absolute. In the signed-store family, the signing key itself, enterprise enrollment profiles, developer mode, and permission to install outside the store are each an item; if one of them is enabled, part of the deny results turns into admin, and the 9 in the last row drops.

This is not a flaw in the model but a limit, and it determines how the model should be used. The table measures not a family but a family’s default configuration. Applying the number to a machine starts with two questions: how many items on this machine are enabled that turn deny results into admin, and who can change those items. If the answer to the second question is “the admin,” the signed-store family’s 9 is not really 9.

The same limitation works in the other direction too. The “requests unreachable even as admin” number, written as 1 in the discrete-permission family, rises in an installation with a mandatory access control layer added; that layer is another way of splitting privilege. The family name gives an upper bound; the installation gives the real number. This is why the next lesson measures the installation itself, not the family.

The Same Family, Two Installations

All of the measurement network’s field laptops belong to the same family, but not all of them give the same number. If one uses a standard user account and another does its daily work with the admin account, the scenario’s first stage starts directly at the second stage on the latter: the compromised account is already on the far side of the boundary, and the item required to cross the admin boundary is not 1 but 0.

This is the software-side counterpart of the zero threshold from the previous lesson. Zero says not that the boundary is weak but that it was never established. In this case, the choice of family changes nothing: even in the strictest model, doing daily work with the admin account moves the table’s admin column into the grant column, and the 4, 11, 12 gap among the three families is largely erased.

The Cost: Legitimate Work That Cannot Be Done

The same row, read in reverse, gives the cost of the defense. Among the 9 requests unreachable in the signed-store family are loading a driver, taking a full-disk-read backup, and reading another process’s memory. All three of these are legitimate administrative work: in the measurement network, a meter-reading device’s driver must be loaded, a field laptop’s full backup must be taken, and a process’s memory must be read while investigating a crash.

The model does not count these tasks as “impossible” — it counts them as done somewhere else: the driver is signed and enters the store, the backup is taken with a permission granted per application, the crash record is collected by the operating system’s own mechanism. The cost is not that the work disappears but that each of it is tied to its own approved path — and the number of those paths is 9. In the discrete-permission family this cost is 1; against that, the requests opened once the boundary falls number 13.

The third table shows where this trade-off concentrates. The first two families differ from each other in only 4 requests, and all four of those concern the splitting of privilege. The signed-store family differs from the others in 11 and 12 requests. The request that gives the same result across all three families is only 2: reading one’s own document and reading another user’s document. The common ground is nothing more than the distinction between a user’s own data and someone else’s; everything beyond that depends on the family.

The trade-off does not read in only one direction. In the measurement network, the field laptop and the branch server look at the same table from different places. Code run on the laptop mostly comes from outside, and the user does not maintain the system; there, a high deny count is a gain, not a cost. On the branch server, however, loading drivers, taking full backups, and inspecting memory are the job itself; the same number 9 there means nine separate exception paths, and each exception path is its own item. The same number is a closed path on one machine and a newly opened configuration item on the other. The choice of family is therefore made per machine class, not per organization.

Summary

  • An operating system family is told apart by its security model, not its product name: the response it gives to the same request, and how many items it costs to change that response.
  • 14 requests give a different result across the three families in 4, 11, and 12 items; the request that gives the same result in all three is only 2.
  • Crossing the admin boundary is 1, 2, and 3 items; reaching every request is 1, 6, and 3 items. Split privilege does not raise the height of the boundary — it lengthens the distance beyond it.
  • The requests reached once the boundary falls are 13, 9, and 5. If privilege’s highest point grants everything, a single item opens 13 of 14 requests.
  • The cost is the number of requests unreachable even as admin: 1, 1, and 9. Most of the nine requests closed in the signed-store family are legitimate administrative work, and each is tied to its own approved path.
  • The table measures not a family but the family’s default configuration. If daily work is done with the admin account, the item required to cross the admin boundary drops to 0, and the difference among the families is erased.

Next Step

All three families bring their model with an installation; the results in the table are that installation’s default values. But a default value is not a choice: it is what remains when the person doing the installation selects nothing.

The next lesson looks at that moment. When a clean install finishes, how many items remain open, how many close during initial hardening, and how many can only be closed if the machine is reinstalled.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close