Add option to enable auto-upgrade on Linux/Unix despite CAP_NET_BIND_SERVICE capability #1808

Open
opened 2026-03-04 01:33:39 -05:00 by deekerman · 5 comments
Owner

Originally created by @CampinCarl on GitHub (Jul 25, 2020).

Problem Description

The if statement linked below rightly describes the issue with setting CAP_NET_BIND_SERVICE on binary files in Linux but doesn't account for setting this option using systemd's AmbientCapabilities directive instead, which doesn't require setting the capability on the binary itself.

github.com/AdguardTeam/AdGuardHome@b4aa791513/home/control_update.go (L101-L111)

Proposed Solution

Modify the if statement logic to allow users to override the behavior, perhaps with a command line flag like --allow-auto-update? When combined with the AmbientCapabilities systemd directive, this would allow users to auto upgrade the binary even when running AdGuardHome without root permissions.

Systemd Service File Example

AmbientCapabilities=CAP_NET_BIND_SERVICE

Alternatives Considered

Script the upgrade myself or fork the code, but a native solution would be much easier and a benefit for other Linux users. Thanks for the great application!

Additional Information

Originally created by @CampinCarl on GitHub (Jul 25, 2020). ### Problem Description <!-- Is your feature request related to a problem? Please add a clear and concise description of what the problem is. --> The if statement linked below rightly describes the issue with setting `CAP_NET_BIND_SERVICE` on binary _files_ in Linux but doesn't account for setting this option using _systemd's_ `AmbientCapabilities` directive instead, which doesn't require setting the capability on the binary itself. https://github.com/AdguardTeam/AdGuardHome/blob/b4aa79151315035f0e839d9a710fe4051595acb5/home/control_update.go#L101-L111 ### Proposed Solution <!-- Describe the solution you'd like in a clear and concise manner --> Modify the if statement logic to allow users to override the behavior, perhaps with a command line flag like `--allow-auto-update`? When combined with the AmbientCapabilities systemd directive, this would allow users to auto upgrade the binary even when running AdGuardHome without root permissions. **Systemd Service File Example** ```ini AmbientCapabilities=CAP_NET_BIND_SERVICE ``` ### Alternatives Considered <!-- A clear and concise description of any alternative solutions or features you've considered. --> Script the upgrade myself or fork the code, but a native solution would be much easier and a benefit for other Linux users. Thanks for the great application! ### Additional Information <!-- Add any other context about the problem here. --> - [func getVersionResp][1] - [systemd.exec AmbientCapabilities][2] [1]: https://github.com/AdguardTeam/AdGuardHome/blob/b4aa79151315035f0e839d9a710fe4051595acb5/home/control_update.go#L87-L117 [2]: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#AmbientCapabilities=
Author
Owner

@ameshkov commented on GitHub (Jul 26, 2020):

Modify the if statement logic to allow users to override the behavior, perhaps with a command line flag like --allow-auto-update?

I am not a fan of adding new flags because most people simply wouldn't know about it.

Is there any way to detect this automatically?

@ameshkov commented on GitHub (Jul 26, 2020): > Modify the if statement logic to allow users to override the behavior, perhaps with a command line flag like --allow-auto-update? I am not a fan of adding new flags because most people simply wouldn't know about it. Is there any way to detect this automatically?
Author
Owner

@CampinCarl commented on GitHub (Jul 26, 2020):

That's fair, this is admittedly a bit of an edge case though I'd argue it's the best way to set it up on Linux without root (at least with systemd). Would you consider a configuration file directive instead or is that just as bad/worse?

As for how to detect it, I suspect you'd need to interact with systemd directly to check. I only know a little Go so here's how one could check from the shell.

  1. Check if AdGuard Home is running under systemd and check the service unit's name
    • systemctl status <AdGuardHome PID>; or
    • ps -o unit <AdGuardHome PID>
  2. Check the AmbientCapabilities property using the service unit's name found in step 1
    • systemctl show -p AmbientCapabilities <AdGuardHome Service File>

If the output from step 2 includes cap_net_bind_service then it should be safe to upgrade AdGuard Home.

@CampinCarl commented on GitHub (Jul 26, 2020): That's fair, this is admittedly a bit of an edge case though I'd argue it's the best way to set it up on Linux without root (at least with systemd). Would you consider a configuration file directive instead or is that just as bad/worse? As for how to detect it, I suspect you'd need to interact with systemd directly to check. I only know a little Go so here's how one could check from the shell. 1. Check if AdGuard Home is running under systemd and check the service unit's name - `systemctl status <AdGuardHome PID>`; or - `ps -o unit <AdGuardHome PID>` 2. Check the AmbientCapabilities property using the service unit's name found in step 1 - `systemctl show -p AmbientCapabilities <AdGuardHome Service File>` If the output from step 2 includes `cap_net_bind_service` then it should be safe to upgrade AdGuard Home.
Author
Owner

@Aikatsui commented on GitHub (Jul 26, 2020):

#813 - automatic update.

@Aikatsui commented on GitHub (Jul 26, 2020): #813 - automatic update.
Author
Owner

@ameshkov commented on GitHub (Jul 30, 2020):

Well, we can run shell commands from Go, it's a perfectly viable solution.

We will need to implement a method that will call your commands one by one, something like util.HaveAmbientCapabilities() and use it.

Something like this:

if runtime.GOOS != "linux" {
    return false;
}

cmd := "systemctl status " + os.Getpid()
if cmd, e := exec.Run(cmd, nil, nil, exec.DevNull, exec.Pipe, exec.MergeWithStdout); e == nil {
    b, _ := ioutil.ReadAll(cmd.Stdout)
    output := string(b)

    // parse, find config file
    // read the config file, check the capabilities
}

Marked as "help wanted" for now that means that we're looking for anyone who can contribute this change to AGH.
If it gets more upvotes and no one volunteers to implement it, we'll do it.

@ameshkov commented on GitHub (Jul 30, 2020): Well, we can run shell commands from Go, it's a perfectly viable solution. We will need to implement a method that will call your commands one by one, something like `util.HaveAmbientCapabilities()` and use it. Something like this: ``` if runtime.GOOS != "linux" { return false; } cmd := "systemctl status " + os.Getpid() if cmd, e := exec.Run(cmd, nil, nil, exec.DevNull, exec.Pipe, exec.MergeWithStdout); e == nil { b, _ := ioutil.ReadAll(cmd.Stdout) output := string(b) // parse, find config file // read the config file, check the capabilities } ``` Marked as "help wanted" for now that means that we're looking for anyone who can contribute this change to AGH. If it gets more upvotes and no one volunteers to implement it, we'll do it.
Author
Owner

@CampinCarl commented on GitHub (Jul 30, 2020):

That makes sense; thanks for the insight. I'm a bit of a novice with Go but I'll play with it and see if I can't get something working.

@CampinCarl commented on GitHub (Jul 30, 2020): That makes sense; thanks for the insight. I'm a bit of a novice with Go but I'll play with it and see if I can't get something working.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/AdGuardHome#1808
No description provided.