Skip to content

Instantly share code, notes, and snippets.

@oxavelar
Last active July 5, 2025 02:51
Show Gist options
  • Save oxavelar/0f52045f80ceda1b1379b2ed749e64b9 to your computer and use it in GitHub Desktop.
Save oxavelar/0f52045f80ceda1b1379b2ed749e64b9 to your computer and use it in GitHub Desktop.
Synology DSM DS920+ System Optimizations
#!/bin/sh
# /usr/local/etc/rc.d/boot-tweaks.sh
#
# Put this in /usr/local/etc/rc.d/
# chown this to root
# chmod this to 700
# Must be run as root!
case $1 in
start)
# Enable NVMe as system + swap
# > mdadm --grow /dev/md0 --raid-devices=6 --force # sys
# > mdadm --grow /dev/md1 --raid-devices=6 --force # swp
mdadm --add /dev/md0 /dev/nvme0n1p1 /dev/nvme1n1p1
mdadm --add /dev/md1 /dev/nvme0n1p2 /dev/nvme1n1p2
for disk in $(find /sys/block/md[0-1]/ -name 'dev-sata[0-9]p[0-9]'); do
echo writemostly > "$disk/state"
done
# System optimizations
sysctl --system
mount -o noatime,remount /
# Reduce writes
# systemctl stop syslog-ng
# Power savings
hdparm -S 120 /dev/sata[0-9]
for raid in $(find /sys/block -name '^md[0-9]$'); do
(cd $raid
echo deadline > "$raid/queue/scheduler"
echo 256 > "$raid/queue/nr_requests"
echo 2 > "$raid/queue/rq_affinity"
echo 2048 > "$raid/queue/read_ahead_kb"
);
done
for disk in $(find /sys/block -name 'sata[0-9]'); do
(cd $disk
echo deadline > "$disk/queue/scheduler"
echo 256 > "$disk/queue/nr_requests"
echo 2 > "$disk/queue/rq_affinity"
echo 2048 > "$disk/queue/read_ahead_kb"
);
done
# Speed-up any re-builds
echo 200000 > /proc/sys/dev/raid/speed_limit_min
echo 800000 > /proc/sys/dev/raid/speed_limit_max
# Tailscale
if ! [ -c /dev/net/tun ]; then
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 0666 /dev/net/tun
fi
;;
stop)
;;
*)
echo "usage: $0 [start|stop]"
;;
esac
#!/bin/sh
# /usr/local/etc/rc.d/boot-tweaks.sh
#
# Put this in /usr/local/etc/rc.d/
# chown this to root
# chmod this to 700
# Must be run as root!
case $1 in
start)
sleep 300
exec /usr/bin/env python -u - "$@" <<'EOF'
# Python code starts here
import os
import re
import sys
import time
import struct
import subprocess
from ctypes import *
from collections import namedtuple
SCEMD_PATH = "/usr/syno/bin/scemd"
SYNOSTORAGED_PATH = "/usr/syno/sbin/synostoraged"
# patches is a list of tuples (orig_pattern, new_pattern, description)
BinaryPatchSet = namedtuple("BinaryPatchSet",
["process_name", "binary_path", "patches"])
scemd_patchset = BinaryPatchSet("scemd", SCEMD_PATH, [
(b'\x48\x89\xDE\xBF\x01\x00\x00\x00\x48\x89\x04\\x24\xE8(....)\x48\x89\xDE\xBF\x02\x00\x00\x00\x89\xC5\xE8(....)\x48\x89\xDE\xBF\x07\x00\x00\x00\xE8(....)\x85\xED',
b'\x48\x89\xDE\xBF\x01\x00\x00\x00\x48\x89\x04\x24\xE8\g<01>\x48\x89\xDE\xBF\x02\x00\x00\x00\x89\xC5\xE8\g<02>\x48\x89\xDE\xBF\x0B\x00\x00\x00\xE8\g<03>\x85\xED',
"NVMe I/O HDD hibernation fix for DSM 7.0-7.1"),
(b'\x48\x89\xEE\xBF\x01\x00\x00\x00\x48\x89\x04\\x24\xE8(....)\x48\x89\xEE\xBF\x02\x00\x00\x00\x89\xC3\xE8(....)\x48\x89\xEE\xBF\x07\x00\x00\x00\xE8(....)\x85\xDB',
b'\x48\x89\xEE\xBF\x01\x00\x00\x00\x48\x89\x04\x24\xE8\g<01>\x48\x89\xEE\xBF\x02\x00\x00\x00\x89\xC3\xE8\g<02>\x48\x89\xEE\xBF\x0B\x00\x00\x00\xE8\g<03>\x85\xDB',
"NVMe I/O HDD hibernation fix for DSM 7.2"),
])
synostoraged_patchset = BinaryPatchSet("synostgd-disk", SYNOSTORAGED_PATH, [
(b'\x4C\x89\xEE\xBF\x03\x00\x00\x00\xE8(....)\x85\xC0\x0F\x88(....)\x4C\x89\xEE\xBF\x07\x00\x00\x00\xE8(....)\x85\xC0\x0F\x88(....)\x4C\x89\xEE\xBF\x0B\x00\x00\x00\xE8',
b'\x4C\x89\xEE\xBF\x03\x00\x00\x00\xE8\g<01>\x85\xC0\x0F\x88\g<02>\xEB\x13\xEE\xBF\x07\x00\x00\x00\xE8\g<03>\x85\xC0\x0F\x88\g<04>\x4C\x89\xEE\xBF\x0B\x00\x00\x00\xE8',
"NVMe I/O HDD hibernation fix for DSM 7.0-7.1"),
(b'\x48\x89\xDE\xBF\x03\x00\x00\x00\xE8(....)\x85\xC0\x0F\x88(....)\x48\x89\xDE\xBF\x07\x00\x00\x00\xE8(....)\x85\xC0\x0F\x88(....)\x48\x89\xDE\xBF\x0B\x00\x00\x00\xE8',
b'\x48\x89\xDE\xBF\x03\x00\x00\x00\xE8\g<01>\x85\xC0\x0F\x88\g<02>\xEB\x13\xDE\xBF\x07\x00\x00\x00\xE8\g<03>\x85\xC0\x0F\x88\g<04>\x48\x89\xDE\xBF\x0B\x00\x00\x00\xE8',
"NVMe I/O HDD hibernation fix for DSM 7.2"),
])
def get_pid_by_proc_name(process_name):
try:
return int(subprocess.check_output(["pidof", process_name]))
except:
return None
ProcMapEntry = namedtuple("ProcMapEntry", ["start", "end", "perm", "offset", "dev", "inode", "pathname"])
def parse_proc_maps(pid):
entries = []
maps_line_re = re.compile(r"(?P<start>[\da-f]+)-(?P<end>[\da-f]+)\s(?P<perm>\S+)\s(?P<offset>[\da-f]+)\s(?P<dev>\S+)\s+(?P<inode>\d+)\s+(?P<pathname>.*)$")
try:
with open(f"/proc/{pid}/maps", "r") as f:
for line in f.readlines():
m = maps_line_re.match(line)
if not m:
continue
start, end, perm, offset, dev, inode, pathname = m.groups()
entries.append(ProcMapEntry(
start = int(start, 16),
end = int(end, 16),
perm = perm,
offset = int(offset, 16),
dev = dev,
inode = inode,
pathname = pathname.strip()))
except:
pass
return entries
def get_module_base_addr(pid, module_name):
entries = parse_proc_maps(pid)
if not entries:
return None
filtered = [entry for entry in entries
if os.path.basename(entry.pathname) == module_name]
if not filtered:
return None
for entry in filtered:
if entry.offset == 0:
return entry.start
return None
def get_binary_patch_changelist(fpath, search_ptrn, replace_ptrn, max_matches=0):
changes = []
try:
with open(fpath, "rb") as f:
data = f.read()
except:
print(f"cannot read {fpath}")
return None
nmatches = len(re.findall(search_ptrn, data, flags=re.DOTALL))
if not nmatches:
return None
elif max_matches and nmatches > max_matches:
print("too many matches encountered")
return None
new_data = re.sub(search_ptrn, replace_ptrn, data, flags=re.DOTALL)
assert(len(new_data) == len(data))
new_bytes = bytearray()
orig_bytes = bytearray()
changes_offset = 0
in_same = True
for i in range(len(data)):
if in_same:
if new_data[i] == data[i]:
continue
else:
changes_offset = i
new_bytes = [new_data[i]]
orig_bytes = [data[i]]
in_same = False
else:
if new_data[i] != data[i]:
new_bytes.append(new_data[i])
orig_bytes.append(data[i])
else:
changes.append((changes_offset, bytes(orig_bytes), bytes(new_bytes)))
new_bytes = orig_bytes = []
in_same = True
if not in_same and new_bytes:
changes.append((changes_offset, bytes(orig_bytes), bytes(new_bytes)))
return changes
libc = None
PTRACE_PEEKDATA = 2
PTRACE_POKEDATA = 5
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
class iovec(Structure):
_fields_ = [("iov_base", c_void_p),
("iov_len", c_size_t)]
def init_ptrace():
global libc
libc = CDLL("libc.so.6")
libc.process_vm_readv.argtypes = [c_uint64, POINTER(iovec), c_ulong,
POINTER(iovec), c_ulong, c_ulong]
libc.process_vm_readv.restype = c_ssize_t
libc.ptrace.argtypes = [c_uint64, c_uint64, c_void_p, c_void_p]
libc.ptrace.restype = c_uint64
libc.__errno_location.restype = POINTER(c_int)
def read_mem_sg_list(pid, addrs_and_lens):
iovcnt = len(addrs_and_lens)
total_bytes = 0
iovec_arr_type = iovec * iovcnt
local_iov = iovec_arr_type()
remote_iov = iovec_arr_type()
readbufs = []
for i, (vaddr, part_len) in enumerate(addrs_and_lens):
total_bytes += part_len
entry_buf = create_string_buffer(part_len)
readbufs.append(entry_buf)
remote_iov[i] = iovec(c_void_p(vaddr), part_len)
local_iov[i] = iovec(cast(entry_buf, c_void_p), part_len)
ret = libc.process_vm_readv(pid, local_iov, iovcnt, remote_iov, iovcnt, 0)
if ret < 0 or ret != total_bytes:
print("failed to read remote process memory")
return []
return [buf.raw for buf in readbufs]
def write_mem_sg_list(pid, sg_list):
ret = libc.ptrace(PTRACE_ATTACH, pid, None, None)
if ret < 0:
print(f"ptrace attach failed for pid {pid}")
return False
_, status = os.waitpid(pid, 0)
if not os.WIFSTOPPED(status):
print(f"ptrace stop failed for pid {pid}")
return False
result = True
for i, (vaddr, part_bytes) in enumerate(sg_list):
part_len = len(part_bytes)
for offset in range(0, part_len, 8):
val = libc.ptrace(PTRACE_PEEKDATA, pid, c_void_p(vaddr+offset), None)
if part_len - offset >= 8:
data = part_bytes[offset:offset+8]
else:
nbytes_left = part_len - offset
orig_bytes = struct.pack('<Q', val)
data = part_bytes[offset:offset+nbytes_left] + orig_bytes[nbytes_left:]
val = struct.unpack("<Q", data)[0]
ret = libc.ptrace(PTRACE_POKEDATA, pid, c_void_p(vaddr+offset), c_void_p(val))
if ret < 0:
print(f"ptrace write mem failed for pid {pid}, addr {vaddr+offset:#x}")
result = False
break
ret = libc.ptrace(PTRACE_DETACH, pid, None, None)
if ret < 0:
print(f"ptrace detach failed for pid {pid}")
return result
def apply_in_memory_patches(pid, base_addr, changelist):
in_list = [(base_addr+offset, len(orig_bytes)) for offset, orig_bytes, _ in changelist]
out_list = read_mem_sg_list(pid, in_list)
if not out_list:
print(f"failed reading memory for pid {pid}")
return False
matched_original = True
matched_patched = True
for i, entry in enumerate(out_list):
if matched_original and entry != changelist[i][1]:
matched_original = False
if matched_patched and entry != changelist[i][2]:
matched_patched = False
if matched_patched:
print(f"pid {pid} already has in-memory patches applied")
return False
if not matched_original:
print(f"encountered memory content mismatch for pid {pid}")
return False
write_list = [(base_addr+offset, new_bytes) for offset, _, new_bytes in changelist]
print(f"applying in-memory patches for pid {pid}")
return write_mem_sg_list(pid, write_list)
def apply_binary_patchset(patchset):
proc_name = patchset.process_name
mod_fname = os.path.basename(patchset.binary_path)
pid = get_pid_by_proc_name(proc_name)
if not pid:
print(f"cannot find pid of {proc_name} process")
return False
image_base = get_module_base_addr(pid, mod_fname)
if not image_base:
print(f"cannot find {mod_fname} image base")
return False
matched_any = False
all_success = True
for orig_pattern, new_pattern, patch_descr in patchset.patches:
changelist = get_binary_patch_changelist(patchset.binary_path,
orig_pattern,
new_pattern,
max_matches=1)
if changelist:
matched_any = True
rc = apply_in_memory_patches(pid, image_base, changelist)
if not rc:
all_success = False
print(f"failed or skipped applying patch '{patch_descr}' for {proc_name}")
else:
print(f"successfully applied patch '{patch_descr}' for {proc_name}")
return matched_any and all_success
def do_in_memory_fixes():
init_ptrace()
apply_binary_patchset(scemd_patchset)
apply_binary_patchset(synostoraged_patchset)
if __name__ == "__main__":
print("applying live in-memory patches...")
do_in_memory_fixes()
# Python code ends here
EOF
;;
stop)
;;
*)
echo "usage: $0 [start|stop]"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment