pax_global_header 0000666 0000000 0000000 00000000064 14774320273 0014523 g ustar 00root root 0000000 0000000 52 comment=1a5085c31a4e15b371e632a67b5c93a180901e0a
landrun-0.1.15/ 0000775 0000000 0000000 00000000000 14774320273 0013252 5 ustar 00root root 0000000 0000000 landrun-0.1.15/.github/ 0000775 0000000 0000000 00000000000 14774320273 0014612 5 ustar 00root root 0000000 0000000 landrun-0.1.15/.github/workflows/ 0000775 0000000 0000000 00000000000 14774320273 0016647 5 ustar 00root root 0000000 0000000 landrun-0.1.15/.github/workflows/build.yml 0000664 0000000 0000000 00000001122 14774320273 0020465 0 ustar 00root root 0000000 0000000 name: Build
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24.1"
check-latest: true
- name: Install dependencies
run: go mod download
- name: Build
run: go build -v -o landrun ./cmd/landrun/main.go
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: landrun-linux-amd64
path: ./landrun
landrun-0.1.15/.github/workflows/go-compatibility.yml 0000664 0000000 0000000 00000000776 14774320273 0022660 0 ustar 00root root 0000000 0000000 name: Go version compatibility
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
go: ["1.18", "1.20", "1.22", "1.24"]
name: Go ${{ matrix.go }} build
steps:
- uses: actions/checkout@v3
- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
- name: Download dependencies
run: go mod tidy
- name: Build landrun
run: go build ./cmd/landrun
landrun-0.1.15/.gitignore 0000664 0000000 0000000 00000001106 14774320273 0015240 0 ustar 00root root 0000000 0000000 # If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
go.work.sum
# env file
.env
main
tmp
internal/sandbox/test_rw
internal/sandbox/test_ro
test_env
landrun landrun-0.1.15/LICENSE 0000664 0000000 0000000 00000002056 14774320273 0014262 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2025 Armin ranjbar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
landrun-0.1.15/README.md 0000664 0000000 0000000 00000033607 14774320273 0014542 0 ustar 00root root 0000000 0000000 # Landrun
A lightweight, secure sandbox for running Linux processes using Landlock. Think firejail, but with kernel-level security and minimal overhead.
Linux Landlock is a kernel-native security module that lets unprivileged processes sandbox themselves.
Landrun is designed to make it practical to sandbox any command with fine-grained filesystem and network access controls. No root. No containers. No SELinux/AppArmor configs.
It's lightweight, auditable, and wraps Landlock v5 features (file access + TCP restrictions).
## Features
- 🔒 Kernel-level security using Landlock
- 🚀 Lightweight and fast execution
- 🛡️ Fine-grained access control for directories and files
- 🔄 Support for read and write paths
- ⚡ Path-specific execution permissions
- 🌐 TCP network access control (binding and connecting)
## Demo
## Requirements
- Linux kernel 5.13 or later with Landlock enabled
- Linux kernel 6.7 or later for network restrictions (TCP bind/connect)
- Go 1.18 or later (for building from source)
## Installation
### Quick Install
```bash
go install github.com/zouuup/landrun/cmd/landrun@latest
```
### From Source
```bash
git clone https://github.com/zouuup/landrun.git
cd landrun
go build -o landrun cmd/landrun/main.go
sudo cp landrun /usr/local/bin/
```
### Distros
#### Arch (AUR)
maintained by [Vcalv](https://github.com/vcalv)
[AUR](https://aur.archlinux.org/packages/landrun-git)
```bash
yay -S landrun
```
#### Slackware
maintained by [r1w1s1](https://github.com/r1w1s1)
[Slackbuild](https://slackbuilds.org/repository/15.0/network/landrun/?search=landrun)
```bash
sudo sbopkg -i packagename
```
## Usage
Basic syntax:
```bash
landrun [options] [args...]
```
### Options
- `--ro `: Allow read-only access to specified path (can be specified multiple times or as comma-separated values)
- `--rox `: Allow read-only access with execution to specified path (can be specified multiple times or as comma-separated values)
- `--rw `: Allow read-write access to specified path (can be specified multiple times or as comma-separated values)
- `--rwx `: Allow read-write access with execution to specified path (can be specified multiple times or as comma-separated values)
- `--bind-tcp `: Allow binding to specified TCP port (can be specified multiple times or as comma-separated values)
- `--connect-tcp `: Allow connecting to specified TCP port (can be specified multiple times or as comma-separated values)
- `--env `: Environment variable to pass to the sandboxed command (format: KEY=VALUE or just KEY to pass current value)
- `--best-effort`: Use best effort mode, falling back to less restrictive sandbox if necessary [default: disabled]
- `--log-level `: Set logging level (error, info, debug) [default: "error"]
- `--unrestricted-network`: Allows unrestricted network access (disables all network restrictions)
- `--unrestricted-filesystem`: Allows unrestricted filesystem access (disables all filesystem restrictions)
- `--add-exec`: Automatically adds the executing binary to --rox
- `--ldd`: Automatically adds required libraries to --rox
### Important Notes
- You must explicitly add the directory or files to the command you want to run with `--rox` flag
- For system commands, you typically need to include `/usr/bin`, `/usr/lib`, and other system directories
- Use `--rwx` for directories or files where you need both write access and the ability to execute files
- Network restrictions require Linux kernel 6.7 or later with Landlock ABI v4
- By default, no environment variables are passed to the sandboxed command. Use `--env` to explicitly pass environment variables
- The `--best-effort` flag allows graceful degradation on older kernels that don't support all requested restrictions
- Paths can be specified either using multiple flags or as comma-separated values (e.g., `--ro /usr,/lib,/home`)
- If no paths or network rules are specified and neither unrestricted flag is set, landrun will apply maximum restrictions (denying all access)
### Environment Variables
- `LANDRUN_LOG_LEVEL`: Set logging level (error, info, debug)
### Examples
1. Run a command that allows exec access to a specific file
```bash
landrun --rox /usr/bin/ls --rox /usr/lib --ro /home ls /home
```
2. Run a command with read-only access to a directory:
```bash
landrun --rox /usr/ --ro /path/to/dir ls /path/to/dir
```
3. Run a command with write access to a directory:
```bash
landrun --rox /usr/bin --ro /lib --rw /path/to/dir touch /path/to/dir/newfile
```
4. Run a command with write access to a file:
```bash
landrun --rox /usr/bin --ro /lib --rw /path/to/dir/newfile touch /path/to/dir/newfile
```
5. Run a command with execution permissions:
```bash
landrun --rox /usr/ --ro /lib,/lib64 /usr/bin/bash
```
6. Run with debug logging:
```bash
landrun --log-level debug --rox /usr/ --ro /lib,/lib64,/path/to/dir ls /path/to/dir
```
7. Run with network restrictions:
```bash
landrun --rox /usr/ --ro /lib,/lib64 --bind-tcp 8080 --connect-tcp 80 /usr/bin/my-server
```
This will allow the program to only bind to TCP port 8080 and connect to TCP port 80.
8. Run a DNS client with appropriate permissions:
```bash
landrun --log-level debug --ro /etc,/usr --rox /usr/ --connect-tcp 443 nc kernel.org 443
```
This allows connections to port 443, requires access to /etc/resolv.conf for resolving DNS.
9. Run a web server with selective network permissions:
```bash
landrun --rox /usr/bin --ro /lib,/lib64,/var/www --rwx /var/log --bind-tcp 80,443 /usr/bin/nginx
```
10. Running anything without providing parameters is... maximum security jail!
```bash
landrun ls
```
11. If you keep getting permission denied without knowing what exactly going on, best to use strace with it.
```bash
landrun --rox /usr strace -f -e trace=all ls
```
12. Run with specific environment variables:
```bash
landrun --rox /usr --ro /etc --env HOME --env PATH --env CUSTOM_VAR=my_value -- env
```
13. Run command with explicity access to files instead of directories:
```bash
landrun --rox /usr/lib/libc.so.6 --rox /usr/lib64/ld-linux-x86-64.so.2 --rox /usr/bin/true /usr/bin/true
```
14. Run a command with --add-exec which automatically adds target binary to --rox
```bash
landrun --rox /usr/lib/ --add-exec /usr/bin/true
```
15. Run a command with --ldd and --add-exec which automatically adds required libraries and target binary to --rox
```bash
landrun --ldd --add-exec /usr/bin/true
```
Note that shared libs always need exec permission due to how they are loaded, PROT_EXEC on mmap() etc.
This example passes the current HOME and PATH variables, plus a custom variable named CUSTOM_VAR.
## Systemd Integration
landrun can be integrated with systemd to run services with enhanced security. Here's an example of running nginx with landrun:
1. Create a systemd service file (e.g., `/etc/systemd/system/nginx-landrun.service`):
```ini
[Unit]
Description=nginx with landrun sandbox
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/landrun \
--rox /usr/bin,/usr/lib \
--ro /etc/nginx,/etc/ssl,/etc/passwd,/etc/group,/etc/nsswitch.conf \
--rwx /var/log/nginx \
--rwx /var/cache/nginx \
--bind-tcp 80,443 \
/usr/bin/nginx -g 'daemon off;'
Restart=always
User=nginx
Group=nginx
[Install]
WantedBy=multi-user.target
```
2. Enable and start the service:
```bash
sudo systemctl daemon-reload
sudo systemctl enable nginx-landrun
sudo systemctl start nginx-landrun
```
3. Check the service status:
```bash
sudo systemctl status nginx-landrun
```
This configuration:
- Runs nginx with minimal required permissions
- Allows binding to ports 80 and 443
- Provides read-only access to configuration files
- Allows write access only to log and cache directories
- Runs as the nginx user and group
- Automatically restarts on failure
You can adjust the permissions based on your specific needs. For example, if you need to serve static files from `/var/www`, add `--ro /var/www` to the ExecStart line.
## Security
landrun uses Linux's Landlock to create a secure sandbox environment. It provides:
- File system access control
- Directory access restrictions
- Execution control
- TCP network restrictions
- Process isolation
- Default restrictive mode when no rules are specified
Landlock is an access-control system that enables processes to securely restrict themselves and their future children. As a stackable Linux Security Module (LSM), it creates additional security layers on top of existing system-wide access controls, helping to mitigate security impacts from bugs or malicious behavior in applications.
### Landlock Access Control Rights
landrun leverages Landlock's fine-grained access control mechanisms, which include:
**File-specific rights:**
- Execute files (`LANDLOCK_ACCESS_FS_EXECUTE`)
- Write to files (`LANDLOCK_ACCESS_FS_WRITE_FILE`)
- Read files (`LANDLOCK_ACCESS_FS_READ_FILE`)
- Truncate files (`LANDLOCK_ACCESS_FS_TRUNCATE`) - Available since Landlock ABI v3
- IOCTL operations on devices (`LANDLOCK_ACCESS_FS_IOCTL_DEV`) - Available since Landlock ABI v5
**Directory-specific rights:**
- Read directory contents (`LANDLOCK_ACCESS_FS_READ_DIR`)
- Remove directories (`LANDLOCK_ACCESS_FS_REMOVE_DIR`)
- Remove files (`LANDLOCK_ACCESS_FS_REMOVE_FILE`)
- Create various filesystem objects (char devices, directories, regular files, sockets, etc.)
- Refer/reparent files across directories (`LANDLOCK_ACCESS_FS_REFER`) - Available since Landlock ABI v2
**Network-specific rights** (requires Linux 6.7+ with Landlock ABI v4):
- Bind to specific TCP ports (`LANDLOCK_ACCESS_NET_BIND_TCP`)
- Connect to specific TCP ports (`LANDLOCK_ACCESS_NET_CONNECT_TCP`)
### Limitations
- Landlock must be supported by your kernel
- Network restrictions require Linux kernel 6.7 or later with Landlock ABI v4
- Some operations may require additional permissions
- Files or directories opened before sandboxing are not subject to Landlock restrictions
## Kernel Compatibility Table
| Feature | Minimum Kernel Version | Landlock ABI Version |
| ---------------------------------- | ---------------------- | -------------------- |
| Basic filesystem sandboxing | 5.13 | 1 |
| File referring/reparenting control | 5.19 | 2 |
| File truncation control | 6.2 | 3 |
| Network TCP restrictions | 6.7 | 4 |
| IOCTL on special files | 6.10 | 5 |
## Troubleshooting
If you receive "permission denied" or similar errors:
1. Ensure you've added all necessary paths with `--ro` or `--rw`
2. Try running with `--log-level debug` to see detailed permission information
3. Check that Landlock is supported and enabled on your system:
```bash
grep -E 'landlock|lsm=' /boot/config-$(uname -r)
# alternatively, if there are no /boot/config-* files
zgrep -iE 'landlock|lsm=' /proc/config.gz
# another alternate method
grep -iE 'landlock|lsm=' /lib/modules/$(uname -r)/config
```
You should see `CONFIG_SECURITY_LANDLOCK=y` and `lsm=landlock,...` in the output
4. For network restrictions, verify your kernel version is 6.7+ with Landlock ABI v4:
```bash
uname -r
```
## Technical Details
### Implementation
This project uses the [landlock-lsm/go-landlock](https://github.com/landlock-lsm/go-landlock) package for sandboxing, which provides both filesystem and network restrictions. The current implementation supports:
- Read/write/execute restrictions for files and directories
- TCP port binding restrictions
- TCP port connection restrictions
- Best-effort mode for graceful degradation on older kernels
### Best-Effort Mode
When using `--best-effort` (disabled by default), landrun will gracefully degrade to using the best available Landlock version on the current kernel. This means:
- On Linux 6.7+: Full filesystem and network restrictions
- On Linux 6.2-6.6: Filesystem restrictions including truncation, but no network restrictions
- On Linux 5.19-6.1: Basic filesystem restrictions including file reparenting, but no truncation control or network restrictions
- On Linux 5.13-5.18: Basic filesystem restrictions without file reparenting, truncation control, or network restrictions
- On older Linux: No restrictions (sandbox disabled)
When no rules are specified and neither unrestricted flag is set, landrun will apply maximum restrictions available for the current kernel version.
### Tests
The project includes a comprehensive test suite that verifies:
- Basic filesystem access controls (read-only, read-write, execute)
- Directory traversal and path handling
- Network restrictions (TCP bind/connect)
- Environment variable isolation
- System command execution
- Edge cases and regression tests
Run the tests with:
```bash
./test.sh
```
Use `--keep-binary` to preserve the test binary after completion:
```bash
./test.sh --keep-binary
```
Use `--use-system` to test against the system-installed landrun binary:
```bash
./test.sh --use-system
```
## Future Features
Based on the Linux Landlock API capabilities, we plan to add:
- 🔒 Enhanced filesystem controls with more fine-grained permissions
- 🌐 Support for UDP and other network protocol restrictions (when supported by Linux kernel)
- 🔄 Process scoping and resource controls
- 🛡️ Additional security features as they become available in the Landlock API
## Acknowledgements
This project wouldn't exist without:
- [Landlock](https://landlock.io), the kernel security module enabling unprivileged sandboxing - maintained by [@l0kod](https://github.com/l0kod)
- [go-landlock](https://github.com/landlock-lsm/go-landlock), the Go bindings powering this tool - developed by [@gnoack](https://github.com/gnoack)
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
landrun-0.1.15/cmd/ 0000775 0000000 0000000 00000000000 14774320273 0014015 5 ustar 00root root 0000000 0000000 landrun-0.1.15/cmd/landrun/ 0000775 0000000 0000000 00000000000 14774320273 0015460 5 ustar 00root root 0000000 0000000 landrun-0.1.15/cmd/landrun/main.go 0000664 0000000 0000000 00000013236 14774320273 0016740 0 ustar 00root root 0000000 0000000 package main
import (
"os"
osexec "os/exec"
"strings"
"github.com/urfave/cli/v2"
"github.com/zouuup/landrun/internal/exec"
"github.com/zouuup/landrun/internal/log"
"github.com/zouuup/landrun/internal/sandbox"
)
// Version is the current version of landrun
const Version = "0.1.15"
// getLibraryDependencies returns a list of library paths that the given binary depends on
func getLibraryDependencies(binary string) ([]string, error) {
cmd := osexec.Command("ldd", binary)
output, err := cmd.Output()
if err != nil {
return nil, err
}
var libPaths []string
lines := strings.Split(string(output), "\n")
for _, line := range lines {
// Skip empty lines and the first line (usually the binary name)
if line == "" || !strings.Contains(line, "=>") {
continue
}
// Extract the library path
parts := strings.Fields(line)
if len(parts) >= 3 {
libPath := strings.Trim(parts[2], "()")
if libPath != "" {
libPaths = append(libPaths, libPath)
}
}
}
return libPaths, nil
}
func main() {
app := &cli.App{
Name: "landrun",
Usage: "Run a command in a Landlock sandbox",
Version: Version,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "log-level",
Usage: "Set logging level (error, info, debug)",
Value: "error",
EnvVars: []string{"LANDRUN_LOG_LEVEL"},
},
&cli.StringSliceFlag{
Name: "ro",
Usage: "Allow read-only access to this path",
},
&cli.StringSliceFlag{
Name: "rox",
Usage: "Allow read-only access with execution to this path",
},
&cli.StringSliceFlag{
Name: "rw",
Usage: "Allow read-write access to this path",
},
&cli.StringSliceFlag{
Name: "rwx",
Usage: "Allow read-write access with execution to this path",
},
&cli.IntSliceFlag{
Name: "bind-tcp",
Usage: "Allow binding to these TCP ports",
Hidden: false,
},
&cli.IntSliceFlag{
Name: "connect-tcp",
Usage: "Allow connecting to these TCP ports",
Hidden: false,
},
&cli.BoolFlag{
Name: "best-effort",
Usage: "Use best effort mode (fall back to less restrictive sandbox if necessary)",
Value: false,
},
&cli.StringSliceFlag{
Name: "env",
Usage: "Environment variables to pass to the sandboxed command (KEY=VALUE or just KEY to pass current value)",
Value: cli.NewStringSlice(),
},
&cli.BoolFlag{
Name: "unrestricted-filesystem",
Usage: "Allow unrestricted filesystem access",
Value: false,
},
&cli.BoolFlag{
Name: "unrestricted-network",
Usage: "Allow unrestricted network access",
Value: false,
},
&cli.BoolFlag{
Name: "ldd",
Usage: "Automatically detect and add library dependencies to --rox",
Value: false,
},
&cli.BoolFlag{
Name: "add-exec",
Usage: "Automatically add the executable path to --rox",
Value: false,
},
},
Before: func(c *cli.Context) error {
log.SetLevel(c.String("log-level"))
return nil
},
Action: func(c *cli.Context) error {
args := c.Args().Slice()
if len(args) == 0 {
log.Fatal("Missing command to run")
}
// Combine --ro and --rox paths for read-only access
readOnlyPaths := append([]string{}, c.StringSlice("ro")...)
readOnlyPaths = append(readOnlyPaths, c.StringSlice("rox")...)
// Combine --rw and --rwx paths for read-write access
readWritePaths := append([]string{}, c.StringSlice("rw")...)
readWritePaths = append(readWritePaths, c.StringSlice("rwx")...)
// Combine --rox and --rwx paths for executable permissions
readOnlyExecutablePaths := append([]string{}, c.StringSlice("rox")...)
readWriteExecutablePaths := append([]string{}, c.StringSlice("rwx")...)
binary, err := osexec.LookPath(args[0])
if err != nil {
log.Fatal("Failed to find binary: %v", err)
}
// Add command's directory to readOnlyExecutablePaths
if c.Bool("add-exec") {
readOnlyExecutablePaths = append(readOnlyExecutablePaths, binary)
log.Debug("Added executable path: %v", binary)
}
// If --ldd flag is set, detect and add library dependencies
if c.Bool("ldd") {
libPaths, err := getLibraryDependencies(binary)
if err != nil {
log.Fatal("Failed to detect library dependencies: %v", err)
}
// Add library directories to readOnlyExecutablePaths
readOnlyExecutablePaths = append(readOnlyExecutablePaths, libPaths...)
log.Debug("Added library paths: %v", libPaths)
}
cfg := sandbox.Config{
ReadOnlyPaths: readOnlyPaths,
ReadWritePaths: readWritePaths,
ReadOnlyExecutablePaths: readOnlyExecutablePaths,
ReadWriteExecutablePaths: readWriteExecutablePaths,
BindTCPPorts: c.IntSlice("bind-tcp"),
ConnectTCPPorts: c.IntSlice("connect-tcp"),
BestEffort: c.Bool("best-effort"),
UnrestrictedFilesystem: c.Bool("unrestricted-filesystem"),
UnrestrictedNetwork: c.Bool("unrestricted-network"),
}
// Process environment variables
envVars := processEnvironmentVars(c.StringSlice("env"))
if err := sandbox.Apply(cfg); err != nil {
log.Fatal("Failed to apply sandbox: %v", err)
}
return exec.Run(args, envVars)
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal("%v", err)
}
}
// processEnvironmentVars processes the env flag values
func processEnvironmentVars(envFlags []string) []string {
result := []string{}
for _, env := range envFlags {
// If the flag is just a key (no = sign), get the value from the current environment
if !strings.Contains(env, "=") {
if val, exists := os.LookupEnv(env); exists {
result = append(result, env+"="+val)
}
} else {
// Flag already contains the value (KEY=VALUE format)
result = append(result, env)
}
}
return result
}
landrun-0.1.15/demo.gif 0000664 0000000 0000000 00000064203 14774320273 0014672 0 ustar 00root root 0000000 0000000 GIF89a3 !NETSCAPE2.0 !gif.ski !> , 3 ڋH扦ʶ
ĢLnʦ JԪjܮN
(8HXhx)9IYiy '
9JZjz
*k{F+,<\Ia,-=MM\y
.>=n~VO_o3o,0Bp:|YÈ+Zt5ƍ+e2HBG<2ʕ,[| 3̙4kڼ3Ν<{ 4СD=4ҥL:}
5ԩTZ5֭\z
6رd˚=6ڵlۺ}7ܹtڽ7|8>8Ō;~9ɔ+[9͜;{:ѤK>:լ[~
;ٴk۾;ݼ{
<ċ?<̛;=ԫ[=ܻ{>˛?>ۻ?ۿ?`H``
.`>aNHa^ana~b"Hb&b*b.c2Hc6ވc:c>dBIdFdJ.dN> eRNIeV^eZne^~ fbIfffjfn grIgvމgzg~ hJhh.h>
iNJi^ini~
jJjjj
kJkފkk
lKll.l>mNKm^mnm~nKn枋nnoKoދoopLpp
/p?qOLq_qoqr"Lr&r*r.s2Ls6ߌs:s>tBMtFtJ/tN?
uROMuV_uZou^
vbMvfvjvn
wrMwvߍwzw~
xNxx/x?yONy喿_yoyz袏Nz馟zꪯz뮿{N{ߎ{{|O||/|?}OO}_}o}~O~柏~~Oߏ
p,*plJp/jp? " K ! ,
+ @@@000``` ???pppPPPПooo___OOOcccKKKÇ p8Ȥrl:ШtJZV{zxL.zn|Nۛ}go}jyD{[SEl `
P
^\G
HJIJH JQFP
FI
WBdHOYadZ[Y)\ȰÇp
THBH<h{L"Q Y-Tx`qLdy \GV]1"( a@T3`*V(""KٳT8`NlGiA,^$ MDu Nk %jIFQTwE0)A#8di 3A> `7g 9x&