only-office: bar every account but the converter from the state root (issue 1843)

lib (bind-mounted into the container at /var/lib/onlyoffice) was 0711 so
nginx inside the container could reach App_Data/cache, and the module
root above it stayed 0711 too, so any account on the machine could walk
through the root into lib's 0755 directories and 0644 files to read
converted documents. The container never passes through the root — only
the converter process does, to read jwt.secret and
broker-converter.secret — so the root is now 0710, owned by the
converter account: only that account and root pass through it. lib
stays 0711 (1837/AC3).
This commit is contained in:
jochen
2026-10-22 16:34:06 +02:00
parent edb6d3b7d3
commit d0a3784be2
2 changed files with 54 additions and 1 deletions
+52
View File
@@ -125,3 +125,55 @@ func TestLibDirectoryLetsNginxThrough(t *testing.T) {
}
t.Fatal("manifest declares no lib directory")
}
// 1843/AC1 (unit: manifest check)
// Given the catalogue, when only-office's manifest is read, then its state directory (the module
// root, bind-mounted nowhere, so the container never passes through it) is mode 0710 and belongs
// to the converter account — the only host process that reaches through the root to read
// ${dir:state}/jwt.secret and broker-converter.secret — so no other account on the machine can
// pass through it to the converted documents under lib (which stays 0711, 1837/AC3).
func TestStateDirectoryBarsOtherAccounts(t *testing.T) {
raw, err := os.ReadFile("module.json")
if err != nil {
t.Fatalf("reading module.json: %v", err)
}
var m struct {
Resources []struct {
ID string `json:"id"`
Type string `json:"type"`
Mode string `json:"mode"`
Owner string `json:"owner"`
Name string `json:"name"`
} `json:"resources"`
}
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatalf("parsing module.json: %v", err)
}
var converterAccount string
for _, r := range m.Resources {
if r.Type == "user" {
converterAccount = r.Name
}
}
if converterAccount == "" {
t.Fatal("manifest declares no user resource for the converter account")
}
var sawState bool
for _, r := range m.Resources {
if r.ID == "state" && r.Type == "directory" {
sawState = true
if r.Mode != "0710" {
t.Errorf("state directory mode = %q, want 0710", r.Mode)
}
if r.Owner != converterAccount {
t.Errorf("state directory owner = %q, want %q, the converter account (whose own group "+
"the mode's group bit then names)", r.Owner, converterAccount)
}
}
}
if !sawState {
t.Fatal("manifest declares no state directory")
}
}
+2 -1
View File
@@ -144,7 +144,8 @@
{
"id": "state",
"type": "directory",
"mode": "0711",
"mode": "0710",
"owner": "only-office-converter",
"place": ".",
"unknown": "program"
},