Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix v1.2 and v1.3 bugs #1264

Merged
merged 7 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions broadcasts/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/safing/portmaster/netenv"
"github.com/safing/portmaster/updates"
"github.com/safing/spn/access"
"github.com/safing/spn/access/account"
"github.com/safing/spn/captain"
)

Expand Down Expand Up @@ -67,11 +68,16 @@ func collectData() interface{} {
Error: err,
}
} else {
data["Account"] = &Account{
account := &Account{
UserRecord: userRecord,
Active: userRecord.MayUse(""),
UpToDate: userRecord.Meta().Modified > time.Now().Add(-7*24*time.Hour).Unix(),
MayUseSPN: userRecord.MayUseSPN(),
}
// Only add feature IDs when account is active.
if account.Active {
account.FeatureIDs = userRecord.CurrentPlan.FeatureIDs
}
data["Account"] = account
}

// Time running.
Expand Down Expand Up @@ -101,8 +107,9 @@ type Location struct {
// Account holds SPN account matching data.
type Account struct {
*access.UserRecord
UpToDate bool
MayUseSPN bool
Active bool
UpToDate bool
FeatureIDs []account.FeatureID
}

// DataError represents an error getting some matching data.
Expand Down
4 changes: 4 additions & 0 deletions firewall/interception/ebpf/bandwidth/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ func BandwidthStatsWorker(ctx context.Context, collectInterval time.Duration, ba
// Allow the current process to lock memory for eBPF resources.
err := rlimit.RemoveMemlock()
if err != nil {
if ebpfLoadingFailed.Add(1) >= 5 {
log.Warningf("ebpf: failed to remove memlock 5 times, giving up with error %s", err)
return nil
}
return fmt.Errorf("ebpf: failed to remove memlock: %w", err)
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified firewall/interception/ebpf/connection_listener/bpf_bpfeb.o
Binary file not shown.
3 changes: 1 addition & 2 deletions firewall/interception/ebpf/connection_listener/bpf_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified firewall/interception/ebpf/connection_listener/bpf_bpfel.o
Binary file not shown.
4 changes: 4 additions & 0 deletions firewall/interception/ebpf/connection_listener/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ var ebpfLoadingFailed atomic.Uint32
func ConnectionListenerWorker(ctx context.Context, packets chan packet.Packet) error {
// Allow the current process to lock memory for eBPF resources.
if err := rlimit.RemoveMemlock(); err != nil {
if ebpfLoadingFailed.Add(1) >= 5 {
log.Warningf("ebpf: failed to remove memlock 5 times, giving up with error %s", err)
return nil
}
return fmt.Errorf("ebpf: failed to remove ebpf memlock: %w", err)
}

Expand Down
4 changes: 2 additions & 2 deletions firewall/interception/ebpf/programs/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ int BPF_PROG(tcp_connect, struct sock *sk) {
return 0;
}

// Read PID
tcp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid());
// Read PID (Careful: This is the Thread Group ID in kernel speak!)
tcp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));

// Set protocol
tcp_info->protocol = TCP;
Expand Down
12 changes: 7 additions & 5 deletions netquery/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"encoding/json"
"fmt"
"io"
"path"
"path/filepath"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -124,7 +124,10 @@ func New(dbPath string) (*Database, error) {
return nil, fmt.Errorf("failed to ensure database directory exists: %w", err)
}

historyPath := "file://" + path.Join(historyParentDir.Path, "history.db")
// Get file location of history database.
historyFile := filepath.Join(historyParentDir.Path, "history.db")
// Convert to SQLite URI path.
historyURI := "file:///" + strings.TrimPrefix(filepath.ToSlash(historyFile), "/")

constructor := func(ctx context.Context) (*sqlite.Conn, error) {
c, err := sqlite.OpenConn(
Expand All @@ -137,7 +140,7 @@ func New(dbPath string) (*Database, error) {
return nil, fmt.Errorf("failed to open read-only sqlite connection at %s: %w", dbPath, err)
}

if err := sqlitex.ExecuteTransient(c, "ATTACH DATABASE '"+historyPath+"?mode=ro' AS history", nil); err != nil {
if err := sqlitex.ExecuteTransient(c, "ATTACH DATABASE '"+historyURI+"?mode=ro' AS history", nil); err != nil {
return nil, fmt.Errorf("failed to attach history database: %w", err)
}

Expand Down Expand Up @@ -180,7 +183,7 @@ func New(dbPath string) (*Database, error) {
readConnPool: pool,
Schema: schema,
writeConn: writeConn,
historyPath: historyPath,
historyPath: historyURI,
}, nil
}

Expand All @@ -207,7 +210,6 @@ func NewInMemory() (*Database, error) {
// any data-migrations. Once the history module is implemented this should
// become/use a full migration system -- use zombiezen.com/go/sqlite/sqlitemigration.
func (db *Database) ApplyMigrations() error {
log.Errorf("applying migrations ...")
db.l.Lock()
defer db.l.Unlock()

Expand Down
1 change: 1 addition & 0 deletions netquery/module_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (m *module) prepare() error {
Internal: true,
})

// TODO: Open database in start() phase.
m.Store, err = NewInMemory()
if err != nil {
return fmt.Errorf("failed to create in-memory database: %w", err)
Expand Down
9 changes: 6 additions & 3 deletions network/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,16 @@ func cleanConnections() (activePIDs map[int]struct{}) {
PID: process.UndefinedProcessID,
}, now)

activePIDs[conn.process.Pid] = struct{}{}

// Step 2: mark as ended
if !exists {
// Step 2: mark end
conn.Ended = nowUnix
conn.Save()
}

// If the connection has an associated process, add its PID to the active PID list.
if conn.process != nil {
activePIDs[conn.process.Pid] = struct{}{}
}
case conn.Ended < deleteOlderThan:
// Step 3: delete
// DEBUG:
Expand Down
20 changes: 14 additions & 6 deletions network/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package network

import (
"context"
"errors"
"fmt"
"net"
"strings"
Expand Down Expand Up @@ -338,7 +339,7 @@ func NewConnectionFromDNSRequest(ctx context.Context, fqdn string, cnames []stri
if localProfile := proc.Profile().LocalProfile(); localProfile != nil {
dnsConn.Internal = localProfile.Internal

if err := dnsConn.updateFeatures(); err != nil {
if err := dnsConn.updateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {
log.Tracer(ctx).Warningf("network: failed to check for enabled features: %s", err)
}
}
Expand Down Expand Up @@ -380,7 +381,7 @@ func NewConnectionFromExternalDNSRequest(ctx context.Context, fqdn string, cname
if localProfile := remoteHost.Profile().LocalProfile(); localProfile != nil {
dnsConn.Internal = localProfile.Internal

if err := dnsConn.updateFeatures(); err != nil {
if err := dnsConn.updateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {
log.Tracer(ctx).Warningf("network: failed to check for enabled features: %s", err)
}
}
Expand Down Expand Up @@ -448,7 +449,7 @@ func (conn *Connection) GatherConnectionInfo(pkt packet.Packet) (err error) {
if localProfile := conn.process.Profile().LocalProfile(); localProfile != nil {
conn.Internal = localProfile.Internal

if err := conn.updateFeatures(); err != nil {
if err := conn.updateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {
log.Tracer(pkt.Ctx()).Warningf("network: failed to check for enabled features: %s", err)
}
}
Expand Down Expand Up @@ -656,14 +657,21 @@ func (conn *Connection) Failed(reason, reasonOptionKey string) {
func (conn *Connection) SetVerdict(newVerdict Verdict, reason, reasonOptionKey string, reasonCtx interface{}) (ok bool) {
conn.SetVerdictDirectly(newVerdict)

// Set reason and context.
conn.Reason.Msg = reason
conn.Reason.Context = reasonCtx

// Reset option key.
conn.Reason.OptionKey = ""
conn.Reason.Profile = ""
if reasonOptionKey != "" && conn.Process() != nil {
conn.Reason.OptionKey = reasonOptionKey
conn.Reason.Profile = conn.Process().Profile().GetProfileSource(conn.Reason.OptionKey)

// Set option key if data is available.
if reasonOptionKey != "" {
lp := conn.Process().Profile()
if lp != nil {
conn.Reason.OptionKey = reasonOptionKey
conn.Reason.Profile = lp.GetProfileSource(conn.Reason.OptionKey)
}
}

return true // TODO: remove
Expand Down
3 changes: 2 additions & 1 deletion process/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ func CleanProcessStorage(activePIDs map[int]struct{}) {
// The PID of a process does not change.

// Check if this is a special process.
if p.Pid == UnidentifiedProcessID || p.Pid == SystemProcessID {
switch p.Pid {
case UnidentifiedProcessID, UnsolicitedProcessID, SystemProcessID:
p.profile.MarkStillActive()
continue
}
Expand Down
44 changes: 44 additions & 0 deletions updates/assets/portmaster.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[Unit]
Description=Portmaster by Safing
Documentation=https://safing.io
Documentation=https://docs.safing.io
Before=nss-lookup.target network.target shutdown.target
After=systemd-networkd.service
Conflicts=shutdown.target
Conflicts=firewalld.service
Wants=nss-lookup.target

[Service]
Type=simple
Restart=on-failure
RestartSec=10
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateTmp=yes
PIDFile=/opt/safing/portmaster/core-lock.pid
Environment=LOGLEVEL=info
Environment=PORTMASTER_ARGS=
EnvironmentFile=-/etc/default/portmaster
ProtectSystem=true
#ReadWritePaths=/var/lib/portmaster
#ReadWritePaths=/run/xtables.lock
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
RestrictNamespaces=yes
# In future version portmaster will require access to user home
# directories to verify application permissions.
ProtectHome=read-only
ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
PrivateDevices=yes
AmbientCapabilities=cap_chown cap_kill cap_net_admin cap_net_bind_service cap_net_broadcast cap_net_raw cap_sys_module cap_sys_ptrace cap_dac_override cap_fowner cap_fsetid cap_sys_resource cap_bpf cap_perfmon
CapabilityBoundingSet=cap_chown cap_kill cap_net_admin cap_net_bind_service cap_net_broadcast cap_net_raw cap_sys_module cap_sys_ptrace cap_dac_override cap_fowner cap_fsetid cap_sys_resource cap_bpf cap_perfmon
# SystemCallArchitectures=native
# SystemCallFilter=@system-service @module
# SystemCallErrorNumber=EPERM
ExecStart=/opt/safing/portmaster/portmaster-start --data /opt/safing/portmaster core -- $PORTMASTER_ARGS
ExecStopPost=-/opt/safing/portmaster/portmaster-start recover-iptables

[Install]
WantedBy=multi-user.target
2 changes: 1 addition & 1 deletion updates/helper/electron.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func EnsureChromeSandboxPermissions(reg *updater.ResourceRegistry) error {

return fmt.Errorf("failed to chmod: %w", err)
}
log.Infof("updates: fixed SUID permission for chrome-sandbox")
log.Debugf("updates: fixed SUID permission for chrome-sandbox")

return nil
}
2 changes: 1 addition & 1 deletion updates/helper/updates.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func MandatoryUpdates() (identifiers []string) {

// Stop here if we only want intel data.
if intelOnly.IsSet() {
return
return identifiers
}

// Binaries
Expand Down
6 changes: 3 additions & 3 deletions updates/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,13 @@ func checkForUpdates(ctx context.Context) (err error) {

if err = registry.UpdateIndexes(ctx); err != nil {
err = fmt.Errorf("failed to update indexes: %w", err)
return
return //nolint:nakedret // TODO: Would "return err" work with the defer?
}

err = registry.DownloadUpdates(ctx, !forcedUpdate)
if err != nil {
err = fmt.Errorf("failed to download updates: %w", err)
return
return //nolint:nakedret // TODO: Would "return err" work with the defer?
}

registry.SelectVersions()
Expand All @@ -299,7 +299,7 @@ func checkForUpdates(ctx context.Context) (err error) {
err = registry.UnpackResources()
if err != nil {
err = fmt.Errorf("failed to unpack updates: %w", err)
return
return //nolint:nakedret // TODO: Would "return err" work with the defer?
}

// Purge old resources
Expand Down
8 changes: 8 additions & 0 deletions updates/os_integration_default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:build !linux
// +build !linux

package updates

func upgradeSystemIntegration() error {
return nil
}
Loading