Skip to content

Commit 754a990

Browse files
GeorgeSapkin1715173329
authored andcommitted
adguardhome: run as an unprivileged user
Run AdGuard Home without superuser privileges, by granting the binary capabilities through ujail. AdGuard Home writes new config files, so it must have r/w access to the directory where these files live. Which means existing configs must be migrated to a new directory, /etc/adguardhome, by default. CAP_NET_BIND_SERVICE and CAP_NET_RAW capabilities are based on the official documentation linked below. Link: https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#running-without-superuser-linux-only Signed-off-by: George Sapkin <[email protected]>
1 parent 79f78c0 commit 754a990

File tree

5 files changed

+209
-33
lines changed

5 files changed

+209
-33
lines changed

net/adguardhome/Makefile

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
77

88
PKG_NAME:=adguardhome
99
PKG_VERSION:=0.107.64
10-
PKG_RELEASE:=1
10+
PKG_RELEASE:=2
1111

1212
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
1313
PKG_SOURCE_URL:=https://codeload.github.com/AdguardTeam/AdGuardHome/tar.gz/v$(PKG_VERSION)?
@@ -46,10 +46,11 @@ define Package/adguardhome
4646
TITLE:=Network-wide ads and trackers blocking DNS server
4747
URL:=https://github.com/AdguardTeam/AdGuardHome
4848
DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle
49+
USERID:=adguardhome=853:adguardhome=853
4950
endef
5051

5152
define Package/adguardhome/conffiles
52-
/etc/adguardhome.yaml
53+
/etc/adguardhome/adguardhome.yaml
5354
/etc/config/adguardhome
5455
endef
5556

@@ -72,14 +73,20 @@ endef
7273

7374
define Package/adguardhome/install
7475
$(call GoPackage/Package/Install/Bin,$(1))
75-
$(INSTALL_DIR) $(1)/etc/init.d
76-
$(INSTALL_BIN) ./files/adguardhome.init $(1)/etc/init.d/adguardhome
76+
$(INSTALL_DIR) $(1)/etc/capabilities
77+
$(INSTALL_CONF) ./files/adguardhome.json $(1)/etc/capabilities/adguardhome.json
7778

7879
$(INSTALL_DIR) $(1)/etc/config
79-
$(INSTALL_DATA) ./files/adguardhome.config $(1)/etc/config/adguardhome
80+
$(INSTALL_CONF) ./files/adguardhome.config $(1)/etc/config/adguardhome
81+
82+
$(INSTALL_DIR) $(1)/etc/init.d
83+
$(INSTALL_BIN) ./files/adguardhome.init $(1)/etc/init.d/adguardhome
8084

8185
$(INSTALL_DIR) $(1)/etc/sysctl.d
8286
$(INSTALL_CONF) ./files/adguardhome.sysctl $(1)/etc/sysctl.d/50-adguardhome.conf
87+
88+
$(INSTALL_DIR) $(1)/etc/uci-defaults
89+
$(INSTALL_BIN) ./files/adguardhome.defaults $(1)/etc/uci-defaults/adguardhome
8390
endef
8491

8592
$(eval $(call Download,adguardhome-frontend))
Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
config adguardhome config
2-
option config /etc/adguardhome.yaml
1+
config adguardhome 'config'
2+
# All paths except for PID must be readable by the configured user
3+
option config '/etc/adguardhome/adguardhome.yaml'
34
# Where to store persistent data by AdGuard Home
4-
option workdir /var/lib/adguardhome
5-
option pidfile /run/adguardhome.pid
5+
option workdir '/var/lib/adguardhome'
6+
option pidfile '/run/adguardhome.pid'
7+
option user 'adguardhome'
8+
option group 'adguardhome'
9+
option verbose '0'
10+
# Files and directories that AdGuard Home has read-only access to
11+
# list jail_mount '/etc/ssl/adguardhome.crt'
12+
# list jail_mount '/etc/ssl/adguardhome.key'
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/bin/sh
2+
3+
OLD_CONFIG_FILE=$(uci -q get adguardhome.config.config)
4+
OLD_CONFIG_FILE=${OLD_CONFIG_FILE:-/etc/adguardhome.yaml}
5+
NEW_CONFIG_DIR=/etc/adguardhome
6+
NEW_CONFIG_FILE="$NEW_CONFIG_DIR/adguardhome.yaml"
7+
8+
start_service() {
9+
if ! /etc/init.d/adguardhome running; then
10+
/etc/init.d/adguardhome start
11+
fi
12+
}
13+
14+
stop_service() {
15+
if /etc/init.d/adguardhome running; then
16+
/etc/init.d/adguardhome stop
17+
fi
18+
}
19+
20+
if [ -f "$OLD_CONFIG_FILE" ] && [ "$OLD_CONFIG_FILE" != "$NEW_CONFIG_FILE" ]; then
21+
echo "Old AdGuard Home config found in '$OLD_CONFIG_FILE'"
22+
OLD_CONFIG_DIR=$(dirname "$OLD_CONFIG_FILE")
23+
24+
USER=$(uci -q get adguardhome.config.user)
25+
USER=${USER:-adguardhome}
26+
GROUP=$(uci -q get adguardhome.config.group)
27+
GROUP=${GROUP:-adguardhome}
28+
29+
echo "Using $USER:$GROUP for file ownership."
30+
31+
CUR_CONFIG_FILE="$OLD_CONFIG_FILE"
32+
if [ "$OLD_CONFIG_DIR" = "/etc" ]; then
33+
echo "AdGuard Home config must be stored in its own directory. Migrating..."
34+
stop_service
35+
36+
[ -d "$NEW_CONFIG_DIR" ] || mkdir -m 0700 -p "$NEW_CONFIG_DIR"
37+
mv "$OLD_CONFIG_FILE" "$NEW_CONFIG_FILE"
38+
chown -R "$USER":"$GROUP" "$NEW_CONFIG_DIR"
39+
CUR_CONFIG_FILE="$NEW_CONFIG_FILE"
40+
uci set adguardhome.config.config="$NEW_CONFIG_FILE"
41+
42+
echo "Config migrated to '$NEW_CONFIG_FILE'"
43+
44+
elif [ "$OLD_CONFIG_DIR" != "$NEW_CONFIG_DIR" ]; then
45+
echo "AdGuard Home config is stored in a non-default path. " \
46+
+ "Ensure configured service user '$USER' can access it."
47+
fi
48+
49+
# Use awk to split match on :, remove double quotes and trim leading and
50+
# trailing spaces
51+
cert_path=$(grep certificate_path: "$CUR_CONFIG_FILE" \
52+
| awk -F':' '{gsub(/"/, "", $2); gsub(/^ +| +$/, "", $2); print $2}')
53+
if [ -n "$cert_path" ]; then
54+
echo "Found custom 'certificate_path' pointing to '$cert_path'." \
55+
+ "Ensure configured service user '$USER' can access it."
56+
57+
stop_service
58+
59+
if ! uci -q show adguardhome.config.jail_mount | grep -q "$cert_path"; then
60+
uci add_list adguardhome.config.jail_mount="$cert_path"
61+
fi
62+
fi
63+
64+
private_key_path=$(grep private_key_path: "$CUR_CONFIG_FILE" \
65+
| awk -F':' '{gsub(/"/, "", $2); gsub(/^ +| +$/, "", $2); print $2}')
66+
if [ -n "$private_key_path" ]; then
67+
echo "Found custom 'private_key_path' pointing to '$private_key_path'." \
68+
+ "Ensure configured service user '$USER' can access it."
69+
70+
stop_service
71+
72+
if ! uci -q show adguardhome.config.jail_mount | grep -q "$private_key_path"; then
73+
uci add_list adguardhome.config.jail_mount="$private_key_path"
74+
fi
75+
fi
76+
77+
uci commit adguardhome
78+
start_service
79+
80+
elif [ "$OLD_CONFIG_FILE" != "$NEW_CONFIG_FILE" ]; then
81+
echo "Old AdGuard Home config not found in '$OLD_CONFIG_FILE'"
82+
stop_service
83+
84+
# Service script will create the new config directory
85+
uci set adguardhome.config.config="$NEW_CONFIG_FILE"
86+
echo "Config path changed to '$NEW_CONFIG_FILE'"
87+
88+
uci commit adguardhome
89+
start_service
90+
91+
else
92+
echo "AdGuard Home config is in its default path '$NEW_CONFIG_FILE'. Nothing to do."
93+
fi
Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/bin/sh /etc/rc.common
2+
# shellcheck disable=SC3043 # ash supports local
23

34
PROG=/usr/bin/AdGuardHome
45

@@ -10,34 +11,80 @@ START=19
1011
STOP=89
1112

1213
boot() {
13-
adguardhome_boot=1
14-
start "$@"
14+
ADGUARDHOME_BOOT=1
15+
start "$@"
1516
}
1617

1718
start_service() {
18-
if [ -n "$adguardhome_boot" ]; then
19-
# Do not start yet, wait for triggers
20-
return 0
21-
fi
22-
23-
config_load adguardhome
24-
config_get CONFIG_FILE config config "/etc/adguardhome.yaml"
25-
config_get PID_FILE config pidfile "/run/adguardhome.pid"
26-
config_get WORK_DIR config workdir "/var/lib/adguardhome"
27-
28-
[ -d "$WORK_DIR" ] || mkdir -m 0755 -p "$WORK_DIR"
29-
30-
procd_open_instance
31-
procd_set_param command "$PROG" -c "$CONFIG_FILE" -w "$WORK_DIR" --pidfile "$PID_FILE" --no-check-update
32-
procd_set_param stdout 1
33-
procd_set_param stderr 1
34-
procd_close_instance
19+
if [ -n "$ADGUARDHOME_BOOT" ]; then
20+
# Do not start yet, wait for triggers
21+
return 0
22+
fi
23+
24+
local config_file
25+
local group
26+
local pid_file
27+
local user
28+
local verbose
29+
local work_dir
30+
31+
config_load adguardhome
32+
config_get config_file config config "/etc/adguardhome/adguardhome.yaml"
33+
config_get work_dir config workdir "/var/lib/adguardhome"
34+
config_get pid_file config pidfile "/run/adguardhome.pid"
35+
config_get_bool verbose config verbose
36+
37+
config_get user config user adguardhome
38+
config_get group config group adguardhome
39+
40+
local config_dir
41+
config_dir=$(dirname "$config_file")
42+
if [ "$config_dir" = '/etc' ]; then
43+
echo "AdGuard Home config must be stored in its own directory, and not in /etc" >&2
44+
exit 1
45+
fi
46+
mkdir -m 0700 -p "$config_dir"
47+
chown -R "$user":"$group" "$config_dir"
48+
49+
mkdir -m 0700 -p "$work_dir"
50+
chown -R "$user":"$group" "$work_dir"
51+
52+
procd_open_instance
53+
54+
procd_set_param command "$PROG"
55+
procd_append_param command --config "$config_file"
56+
procd_append_param command --work-dir "$work_dir"
57+
procd_append_param command --logfile syslog
58+
procd_append_param command --no-check-update
59+
[ "$verbose" = 1 ] && procd_append_param command --verbose
60+
61+
procd_set_param pidfile "$pid_file"
62+
procd_set_param stdout 1
63+
procd_set_param stderr 1
64+
procd_set_param user "$user"
65+
procd_set_param group "$group"
66+
procd_set_param capabilities /etc/capabilities/adguardhome.json
67+
procd_set_param no_new_privs 1
68+
69+
# log is needed for logging to syslog instead of stdout
70+
# procfs is needed to readlink /proc/self/exe
71+
procd_add_jail adguardhome log procfs
72+
73+
# config directory must be writable to write new config files
74+
procd_add_jail_mount_rw "$config_dir"
75+
procd_add_jail_mount_rw "$work_dir"
76+
77+
procd_add_jail_mount /etc/hosts
78+
procd_add_jail_mount /etc/ssl/certs
79+
config_list_foreach config jail_mount procd_add_jail_mount
80+
81+
procd_close_instance
3582
}
3683

3784
service_triggers() {
38-
if [ -n "$adguardhome_boot" ]; then
39-
# Wait for interfaces to be up before starting AdGuard Home for real.
40-
# Prevents issues like https://github.com/openwrt/packages/issues/21868.
41-
procd_add_raw_trigger "interface.*.up" 5000 /etc/init.d/adguardhome restart
42-
fi
85+
if [ -n "$ADGUARDHOME_BOOT" ]; then
86+
# Wait for interfaces to be up before starting AdGuard Home for real.
87+
# Prevents issues like https://github.com/openwrt/packages/issues/21868.
88+
procd_add_raw_trigger "interface.*.up" 5000 /etc/init.d/adguardhome restart
89+
fi
4390
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"bounding": [
3+
"CAP_NET_BIND_SERVICE",
4+
"CAP_NET_RAW"
5+
],
6+
"effective": [
7+
"CAP_NET_BIND_SERVICE",
8+
"CAP_NET_RAW"
9+
],
10+
"ambient": [
11+
"CAP_NET_BIND_SERVICE",
12+
"CAP_NET_RAW"
13+
],
14+
"permitted": [
15+
"CAP_NET_BIND_SERVICE",
16+
"CAP_NET_RAW"
17+
],
18+
"inheritable": [
19+
"CAP_NET_BIND_SERVICE",
20+
"CAP_NET_RAW"
21+
]
22+
}

0 commit comments

Comments
 (0)