Hello, I'm Ganesh. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. Star Us to help devs discover the project. Do give it a try and share your feedback for improving the product.
In previous article we discussed how this feature may be attacker entry point to server.
So, now let's implment custom systemd configuration to disable this feature.
Securing Postgres with systemd.exec options
I found only way for now to disable this feature is to create custom systemd configuration.
Let's identify the postgres version.
gk@jarvis:~$ psql --version
psql (PostgreSQL) 16.13 (Ubuntu 16.13-0ubuntu0.24.04.1)
gk@jarvis:~$
Based on postgress version we can use different postgresctl command.
We can add custom systemd configuration for each postgres version.
So, How attacker mostly use copy function to get inside the server?
Here, how simple funtion can be used to get inside the server.
- using shell
- using curl
- using wget
- using bash
Still goes on Many ways you can use copy function to get inside the server.
Based on my analysis and continuous retry on disable feature on by one.
I got working configureation which will disconnect from postgres access.
Available options In systemd.exec For postgres
Let's analyze these options and try to disable them using systemd.exec options.
we can use
TemporaryFileSystem
This will create read only filesystem for specific directory.
We can make sure they don't have direct access to system utilities.BindReadOnlyPaths
Re-expose only what's needed by postgres. Example postgres binaries, libraries etc.ProtectSystem
Block /usr, /boot, /etc from write accessProtectHome
This will block access to /home directory.PrivateTmp
This will create temporary /tmp and /var/tmp directories for the service.ReadWritePaths
This is main thing as we disabled all the feature postgress data should be writable to some directory. Which can be:
- /var/lib/postgresql
- /var/run/postgresql
- /var/log/postgresql
Just have a look based on your version.
NoNewPrivileges
If a service process tries to gain more privileges, the kernel will deny it.
This can prevent attackers from escalating privileges even if they compromise the service.RestrictNamespaces
This option can be used to restrict the namespaces that a service can access.
This is mainly for if they try to break out from the container/VM.RestrictAddressFamilies
This option can be used to restrict the address families that a service can access.ProtectKernelTunables
This option can be used to prevent a service from modifying kernel tunables.ProtectKernelModules
This option can be used to prevent a service from loading kernel modules.ProtectControlGroups
This will prevent the service from accessing the cgroups of other processes.ProtectProc
This will prevent the service from accessing the process information of other processes.UMask
This will set the umask of the service.CapabilityBoundingSet
This will set the capability bounding set of the service.AmbientCapabilities
This will set the ambient capabilities of the service.SystemCallFilter
This will set the system call filter of the service.SystemCallErrorNumber
This will set the system call error number of the service.MemoryDenyWriteExecute
This will set the memory deny write execute of the service.LockPersonality
This will lock the personality of the service.RestrictSUIDSGID
This will prevent the service from using SUID and SGID bits.
Configuring Systemd for postgres
So, Now let's create custom configuration for postgres.
mkdir -p /etc/systemd/system/postgresql@16-main.service.d
sudo vim /etc/systemd/system/postgresql@16-main.service.d/override.conf
Now add these options to the file.
[Service]
# ── BYPASS pg_ctlcluster (it's a perl script — breaks TemporaryFileSystem) ──
ExecStart=
ExecStart=/usr/lib/postgresql/16/bin/postgres \
-D /var/lib/postgresql/16/main \
-c config_file=/etc/postgresql/16/main/postgresql.conf \
-c hba_file=/etc/postgresql/16/main/pg_hba.conf \
-c ident_file=/etc/postgresql/16/main/pg_ident.conf \
-c external_pid_file=/run/postgresql/16-main.pid
ExecStop=
ExecStop=/usr/lib/postgresql/16/bin/pg_ctl stop -D /var/lib/postgresql/16/main -m fast
ExecReload=
ExecReload=/usr/lib/postgresql/16/bin/pg_ctl reload -D /var/lib/postgresql/16/main
User=postgres
Group=postgres
# ── BLANK ALL EXECUTABLE DIRS ────────────────────────
TemporaryFileSystem=/usr/bin:ro
TemporaryFileSystem=/bin:ro
TemporaryFileSystem=/usr/sbin:ro
TemporaryFileSystem=/sbin:ro
TemporaryFileSystem=/usr/local/bin:ro
TemporaryFileSystem=/usr/local/sbin:ro
TemporaryFileSystem=/snap:ro
TemporaryFileSystem=/opt:ro
# ── RE-EXPOSE ONLY WHAT'S NEEDED ─────────────────────
BindReadOnlyPaths=/usr/lib/postgresql/16/bin/postgres:/usr/lib/postgresql/16/bin/postgres
BindReadOnlyPaths=/usr/lib/postgresql/16/bin/pg_ctl:/usr/lib/postgresql/16/bin/pg_ctl
BindReadOnlyPaths=/usr/lib/postgresql/16/lib:/usr/lib/postgresql/16/lib
BindReadOnlyPaths=/lib/x86_64-linux-gnu:/lib/x86_64-linux-gnu
BindReadOnlyPaths=/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu
# ── FILESYSTEM ───────────────────────────────────────
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/postgresql /var/run/postgresql /var/log/postgresql
# ── BEHAVIORAL ───────────────────────────────────────
NoNewPrivileges=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
ProtectProc=invisible
UMask=0027
CapabilityBoundingSet=
AmbientCapabilities=
# ── SYSCALL FILTER ────────────────────────────────────
SystemCallFilter=@system-service @file-system @network-io
SystemCallErrorNumber=EPERM
MemoryDenyWriteExecute=yes
LockPersonality=yes
RestrictSUIDSGID=yes
Note: There may many issues setting up this configuration. So, make sure this only done on Staging env and test it thoroughly.
sudo systemctl daemon-reload
sudo systemctl restart postgresql@16-main.service
So, If you check status
sudo systemctl status postgresql@16-main.service
You will see all the options are enabled.
If there any issues just check logs
sudo journalctl -u postgresql@16-main.service -f -n 50
Reverting Configuration
Finaly to remove this configuration just run
First we have remove the conf file.
And restart daemon and restart service.
sudo rm /etc/systemd/system/postgresql@16-main.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart postgresql@16-main.service
Conclusion
This is the only way I found to disable copy function in postgres. This may be experimental but still worth for adding this config if you want disable postgress copy to program function.
Reference Man Page Systemd : https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
Discussion in HN: https://news.ycombinator.com/item?id=37164115
PostgreSQL Discussion : https://www.postgresql.org/message-id/CAKFQuwZZ0zAMpp2KjBr5bUS7RvBqouD2Kqne6YtbgZn%3DnzL1xA%40mail.gmail.com
Any feedback or contributors are welcome! It’s online, source-available, and ready for anyone to use.
⭐ Star it on GitHub: https://github.com/HexmosTech/git-lrc

Top comments (0)