Skip to content

Commit b7058b2

Browse files
authored
[v17] [teleport-update] Set umask 0022 for teleport-update to avoid errors on enable (#52755)
* Set umask 0022 for teleport-update * init -> main * refactor * move const * add flag * missed not * fix inequality * remove flag * dead code * docs * docs 2 * feedback
1 parent 855b2af commit b7058b2

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

lib/autoupdate/agent/installer.go

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const (
6464

6565
// LocalInstaller manages the creation and removal of installations
6666
// of Teleport.
67+
// SetRequiredUmask must be called before any methods are executed.
6768
type LocalInstaller struct {
6869
// InstallDir contains each installation, named by version.
6970
InstallDir string

lib/autoupdate/agent/updater.go

+20
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"path/filepath"
3131
"runtime"
3232
"slices"
33+
"syscall"
3334
"time"
3435

3536
"github.com/gravitational/trace"
@@ -57,6 +58,9 @@ const (
5758
reservedFreeDisk = 10_000_000
5859
// debugSocketFileName is the name of Teleport's debug socket in the data dir.
5960
debugSocketFileName = "debug.sock" // 10 MB
61+
// requiredUmask must be set before this package can be used.
62+
// Use syscall.Umask to set when no other goroutines are running.
63+
requiredUmask = 0o022
6064
)
6165

6266
// Log keys
@@ -67,6 +71,20 @@ const (
6771
errorKey = "error"
6872
)
6973

74+
// SetRequiredUmask sets the umask to match the systemd umask that the teleport-update service will execute with.
75+
// This ensures consistent file permissions.
76+
// NOTE: This must be run in main.go before any goroutines that create files are started.
77+
func SetRequiredUmask(ctx context.Context, log *slog.Logger) {
78+
warnUmask(ctx, log, syscall.Umask(requiredUmask))
79+
}
80+
81+
func warnUmask(ctx context.Context, log *slog.Logger, old int) {
82+
if old&^requiredUmask != 0 {
83+
log.WarnContext(ctx, "Restrictive umask detected. Umask has been changed to 0022 for teleport-update and all child processes.")
84+
log.WarnContext(ctx, "All files created by teleport-update will have permissions set according to this umask.")
85+
}
86+
}
87+
7088
// NewLocalUpdater returns a new Updater that auto-updates local
7189
// installations of the Teleport agent.
7290
// The AutoUpdater uses an HTTP client with sane defaults for downloads, and
@@ -174,6 +192,7 @@ type LocalUpdaterConfig struct {
174192
}
175193

176194
// Updater implements the agent-local logic for Teleport agent auto-updates.
195+
// SetRequiredUmask must be called before any methods are executed, except for Status.
177196
type Updater struct {
178197
// Log contains a logger.
179198
Log *slog.Logger
@@ -545,6 +564,7 @@ func isActiveOrEnabled(ctx context.Context, s Process) (bool, error) {
545564

546565
// Status returns all available local and remote fields related to agent auto-updates.
547566
// Status is safe to run concurrently with other Updater commands.
567+
// Status does not write files, and therefore does not require SetRequiredUmask.
548568
func (u *Updater) Status(ctx context.Context) (Status, error) {
549569
var out Status
550570
// Read configuration from update.yaml.

lib/autoupdate/agent/updater_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
package agent
2020

2121
import (
22+
"bytes"
2223
"context"
2324
"encoding/json"
2425
"errors"
26+
"fmt"
27+
"log/slog"
2528
"net/http"
2629
"net/http/httptest"
2730
"os"
@@ -40,6 +43,40 @@ import (
4043
"github.com/gravitational/teleport/lib/utils/testutils/golden"
4144
)
4245

46+
func TestWarnUmask(t *testing.T) {
47+
t.Parallel()
48+
49+
for _, tt := range []struct {
50+
old int
51+
warn bool
52+
}{
53+
{old: 0o000, warn: false},
54+
{old: 0o001, warn: true},
55+
{old: 0o011, warn: true},
56+
{old: 0o111, warn: true},
57+
{old: 0o002, warn: false},
58+
{old: 0o020, warn: false},
59+
{old: 0o022, warn: false},
60+
{old: 0o220, warn: true},
61+
{old: 0o200, warn: true},
62+
{old: 0o222, warn: true},
63+
{old: 0o333, warn: true},
64+
{old: 0o444, warn: true},
65+
{old: 0o555, warn: true},
66+
{old: 0o666, warn: true},
67+
{old: 0o777, warn: true},
68+
} {
69+
t.Run(fmt.Sprintf("old umask %o", tt.old), func(t *testing.T) {
70+
ctx := context.Background()
71+
out := &bytes.Buffer{}
72+
warnUmask(ctx, slog.New(slog.NewTextHandler(out,
73+
&slog.HandlerOptions{ReplaceAttr: msgOnly},
74+
)), tt.old)
75+
assert.Equal(t, tt.warn, strings.Contains(out.String(), "detected"))
76+
})
77+
}
78+
}
79+
4380
func TestUpdater_Disable(t *testing.T) {
4481
t.Parallel()
4582

tool/teleport-update/main.go

+7
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ func Run(args []string) int {
184184
return 1
185185
}
186186

187+
// Set required umask for commands that write files to system directories as root, and warn loudly if it changes.
188+
switch command {
189+
case statusCmd.FullCommand(), versionCmd.FullCommand():
190+
default:
191+
autoupdate.SetRequiredUmask(ctx, plog)
192+
}
193+
187194
switch command {
188195
case enableCmd.FullCommand():
189196
ccfg.Enabled = true

0 commit comments

Comments
 (0)