123 lines
6.6 KiB
Markdown
123 lines
6.6 KiB
Markdown
# Security model
|
|
|
|
LiveWall is a wallpaper app that can run third-party code. This page states plainly what that means,
|
|
what the app does about it, and what it cannot do.
|
|
|
|
## The blunt version
|
|
|
|
A plugin is a .NET assembly loaded **into LiveWall's own process**, with LiveWall's rights. There is
|
|
no sandbox, no separate account, no permission-checking kernel layer. A plugin can:
|
|
|
|
* read and write any file your user account can reach (documents, browser profiles, keys);
|
|
* open network connections and upload whatever it found;
|
|
* change or delete your LiveWall settings and wallpapers;
|
|
* register global hotkeys and log keystrokes of its own (as any process can);
|
|
* crash LiveWall (only the plugin's own failures are contained — see below).
|
|
|
|
The permission list is therefore **informed consent, not a security boundary**. LiveWall enforces it
|
|
where enforcement makes sense (it will not register an overlay without `DesktopOverlay`), and the
|
|
warning dialog shows exactly what a plugin asked for, but a hostile plugin that lies in its manifest
|
|
is only limited by your user account.
|
|
|
|
Install plugins the way you install any other program: from a source you trust, ideally with a
|
|
reviewable repository.
|
|
|
|
## What LiveWall actually does
|
|
|
|
### The warning before anything runs
|
|
|
|
Two gates, both modal, both requiring an explicit acknowledgement:
|
|
|
|
1. **The plugin system itself.** Turning on *Enable the plugin system* shows a full-screen-format
|
|
warning: third-party code, unverified plugins may cause harm to your computer, nothing is
|
|
sandboxed, only proceed with sources you trust. The checkbox must be ticked before *Enable plugins*
|
|
becomes clickable. `ConsentGiven` is stored, so this is asked once per installation.
|
|
|
|
2. **Every single plugin.** Enabling a plugin shows a card with name, author, version, id, folder,
|
|
its **SHA-256 hash**, a verified/unverified verdict, and the full permission list expanded into
|
|
human sentences. Again the acknowledgement must be ticked first.
|
|
|
|
The same warning banner stays visible at the top of the **Plugins** tab permanently — the user is
|
|
never more than one click from the reminder.
|
|
|
|
### Off by default
|
|
|
|
`Plugins.Enabled` is `false` in a fresh configuration, and `AllowUnverified` is `false` as well. With
|
|
both off, nothing in `%APPDATA%\LiveWall\plugins` is loaded at all; the folder is only scanned so the
|
|
list can be shown.
|
|
|
|
### Hash-pinned trust
|
|
|
|
* Every plugin's entry assembly is hashed (SHA-256) at load time.
|
|
* When the user accepts a warning, that exact hash is stored in
|
|
`%APPDATA%\LiveWall\plugin-trust.json` as `{ "<plugin id>": "<sha256>" }`, and mirrored into
|
|
`settings.json` (`Plugins.Plugins[] { Enabled, ApprovedHash }`).
|
|
* If the DLL changes — an update, but also the first sign of tampering — the hash no longer matches,
|
|
the plugin is **unverified** again, and the warning reappears. There is no way to enable a
|
|
mismatched plugin silently: the *Enable* button path always shows the dialog.
|
|
* **Forget trust** (in the row, visible for verified plugins) removes the stored hash; the next
|
|
enable asks again.
|
|
* A manifest may also carry a `checksum`; when present it must match the assembly or the plugin is
|
|
rejected outright (`ChecksumMismatch`), which lets a publisher pin the exact build they shipped.
|
|
|
|
### Failing safely
|
|
|
|
* `Initialize`, every command, page build, filter pass, renderer call, hotkey action and event
|
|
handler is wrapped: exceptions are logged with the plugin id and the offending feature stops being
|
|
used. The plugin shows as **Failed** with the message.
|
|
* A plugin that fails to load is never retried in a loop.
|
|
* A crashing native plugin can still take the process down (as can any in-process code). LiveWall
|
|
logs each step of loading so the culprit is identifiable afterwards.
|
|
* LiveWall never executes a plugin it has not been explicitly told to enable — there is no
|
|
auto-load from a zip, download, or command line.
|
|
|
|
### Isolation of the file system
|
|
|
|
* Plugin data goes to `%APPDATA%\LiveWall\plugin-data\<id>\` (`IPluginStorage`). Folder names are
|
|
sanitised from the plugin id, so `../../Windows` cannot be used to escape.
|
|
* The plugin folder itself is `%APPDATA%\LiveWall\plugins\<folder>\`. Nothing else in the app's own
|
|
data folder is exposed through the SDK except `Storage.PathFor`, which is confined to the plugin's
|
|
data folder.
|
|
|
|
### Assembly loading
|
|
|
|
Plugins are loaded into a **collectible `AssemblyLoadContext`** that has `LiveWall.Sdk` shared with
|
|
the host. This means:
|
|
|
|
* two plugins can ship different versions of the same helper library without colliding;
|
|
* unloading actually releases the assembly, so a fixed plugin can be retried after **Rescan**;
|
|
* a plugin cannot accidentally shadow `LiveWall.Sdk` and hand back the wrong interface type.
|
|
|
|
## What LiveWall does *not* do
|
|
|
|
* It does not sandbox, virtualise or restrict the plugin's file/network/process access.
|
|
* It does not scan plugins for malware, and does not transmit hashes anywhere.
|
|
* It does not "verify" against a public signature: **verified** on this machine means *"this exact
|
|
file is the one you approved"*, not *"this file is trustworthy"*.
|
|
* It does not protect against a plugin that persists (auto-start entry, scheduled task) — check
|
|
`shell:startup`, `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` and Task Scheduler if you
|
|
distrust something you ran.
|
|
* It cannot undo what a plugin already did to your files. Back up first if you are experimenting.
|
|
|
|
## Advice for users
|
|
|
|
1. Turn the plugin system on only when you have a plugin you actually want.
|
|
2. Read the permission list. `FileSystem` + `Network` together is "it can upload my files" — that had
|
|
better be a plugin you trust.
|
|
3. Prefer plugins whose source you can read. A DLL alone is a black box.
|
|
4. If the hash of a plugin you have been using changes after an update, that is expected — but it is
|
|
also exactly what tampering looks like, so treat the new warning as real.
|
|
5. To be sure a plugin is gone: **Disable** it, delete its folder, and delete
|
|
`%APPDATA%\LiveWall\plugin-data\<id>`.
|
|
|
|
## Advice for developers
|
|
|
|
* Declare **all** permissions you use, and nothing else. Over-declaring trains users to click through.
|
|
* Never call `SetWallpaper` in a loop; it reloads media.
|
|
* Don't write outside `context.Storage.DataFolder`. If you need a user-chosen location, ask for it
|
|
explicitly and remember it.
|
|
* Long work belongs on the thread pool; the UI thread stalls the wallpaper and your own overlay.
|
|
* Log through `context.Log`, not to your own file, so everything is in one place for support.
|
|
* Treat the returned `IDisposable`s and `ShutdownToken` seriously: unload happens while the user is
|
|
watching, and a plugin that leaves a timer running keeps the load context alive.
|