Skip to content

Commit 264b068

Browse files
committed
Use semodule -lfull --checksum instead of the datastore
SELinux userspace release 3.4 introduced a new command line option [-m|--checksum] to `semodule` which adds sha256 checksum of modules to its output. It can be used to check whether the same module is already installed or not. Given that selinuxd installed modules use priority 350 we can use semodule checksum and priority 350 as an indicator whether a module was already installed by selinuxd or not and therefore there's no need to track the state of modules in a separate datastore. `semodule --checksum` is supported since Red Hat Enterprise Linux 8.6 Signed-off-by: Petr Lautrbach <[email protected]>
1 parent 730e7f7 commit 264b068

File tree

6 files changed

+68
-51
lines changed

6 files changed

+68
-51
lines changed

pkg/daemon/action.go

+3-31
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package daemon
22

33
import (
4-
"bytes"
5-
"errors"
64
"fmt"
75

86
"github.com/containers/selinuxd/pkg/datastore"
@@ -40,34 +38,14 @@ func (pi *policyInstall) do(modulePath string, sh seiface.Handler, ds datastore.
4038
return "", fmt.Errorf("installing policy: %w", csErr)
4139
}
4240

43-
p, getErr := ds.Get(policyName)
41+
module, getErr := sh.GetPolicyModule(policyName)
4442
// If the checksums are equal, the policy is already installed
4543
// and in an appropriate state
46-
if getErr == nil && bytes.Equal(p.Checksum, cs) {
44+
if getErr == nil && module.Checksum == cs {
4745
return "", nil
48-
} else if getErr != nil && !errors.Is(getErr, datastore.ErrPolicyNotFound) {
49-
return "", fmt.Errorf("installing policy: couldn't access datastore: %w", getErr)
5046
}
5147

5248
installErr := sh.Install(pi.path)
53-
status := datastore.InstalledStatus
54-
var msg string
55-
56-
if installErr != nil {
57-
status = datastore.FailedStatus
58-
msg = installErr.Error()
59-
}
60-
61-
ps := datastore.PolicyStatus{
62-
Policy: policyName,
63-
Status: status,
64-
Message: msg,
65-
Checksum: cs,
66-
}
67-
puterr := ds.Put(ps)
68-
if puterr != nil {
69-
return "", fmt.Errorf("failed persisting status in datastore: %w", puterr)
70-
}
7149

7250
if installErr != nil {
7351
return "", fmt.Errorf("failed executing install action: %w", installErr)
@@ -96,19 +74,13 @@ func (pi *policyRemove) do(modulePath string, sh seiface.Handler, ds datastore.D
9674
}
9775

9876
if !pi.moduleInstalled(sh, policyArg) {
99-
if err := ds.Remove(policyArg); err != nil {
100-
return "Module is not in the system", fmt.Errorf("failed removing policy from datastore: %w", err)
101-
}
10277
return "No action needed; Module is not in the system", nil
10378
}
10479

10580
if err := sh.Remove(policyArg); err != nil {
10681
return "", fmt.Errorf("failed executing remove action: %w", err)
10782
}
10883

109-
if err := ds.Remove(policyArg); err != nil {
110-
return "", fmt.Errorf("failed removing policy from datastore: %w", err)
111-
}
11284
return "", nil
11385
}
11486

@@ -119,7 +91,7 @@ func (pi *policyRemove) moduleInstalled(sh seiface.Handler, policy string) bool
11991
}
12092

12193
for _, mod := range currentModules {
122-
if policy == mod {
94+
if policy == mod.Name {
12395
return true
12496
}
12597
}

pkg/daemon/daemon.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func Daemon(opts *SelinuxdOptions, mPath string, sh seiface.Handler, ds datastor
3939
defer ds.Close()
4040
}
4141

42-
ss, err := initStatusServer(opts.StatusServerConfig, ds.GetReadOnly(), l)
42+
ss, err := initStatusServer(opts.StatusServerConfig, ds.GetReadOnly(), sh, l, mPath)
4343
if err != nil {
4444
l.Error(err, "Unable initialize status server")
4545
panic(err)

pkg/daemon/status_server.go

+22-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"time"
1212

1313
"github.com/containers/selinuxd/pkg/datastore"
14+
seiface "github.com/containers/selinuxd/pkg/semodule/interface"
15+
"github.com/containers/selinuxd/pkg/utils"
1416
"github.com/go-logr/logr"
1517
"github.com/gorilla/mux"
1618
)
@@ -31,12 +33,14 @@ type StatusServerConfig struct {
3133
type statusServer struct {
3234
cfg StatusServerConfig
3335
ds datastore.ReadOnlyDataStore
36+
sh seiface.Handler
3437
l logr.Logger
38+
mPath string
3539
lst net.Listener
3640
ready bool
3741
}
3842

39-
func initStatusServer(cfg StatusServerConfig, ds datastore.ReadOnlyDataStore, l logr.Logger) (*statusServer, error) {
43+
func initStatusServer(cfg StatusServerConfig, ds datastore.ReadOnlyDataStore, sh seiface.Handler, l logr.Logger, mPath string) (*statusServer, error) {
4044
if cfg.Path == "" {
4145
cfg.Path = DefaultUnixSockAddr
4246
}
@@ -48,7 +52,7 @@ func initStatusServer(cfg StatusServerConfig, ds datastore.ReadOnlyDataStore, l
4852
return nil, fmt.Errorf("setting up socket: %w", err)
4953
}
5054

51-
ss := &statusServer{cfg, ds, l, lst, false}
55+
ss := &statusServer{cfg, ds, sh, l, mPath, lst, false}
5256
return ss, nil
5357
}
5458

@@ -111,7 +115,7 @@ func (ss *statusServer) initializeRoutes(r *mux.Router) {
111115
}
112116

113117
func (ss *statusServer) listPoliciesHandler(w http.ResponseWriter, r *http.Request) {
114-
modules, err := ss.ds.List()
118+
modules, err := ss.sh.List()
115119
if err != nil {
116120
http.Error(w, "Cannot list modules", http.StatusInternalServerError)
117121
return
@@ -127,17 +131,28 @@ func (ss *statusServer) listPoliciesHandler(w http.ResponseWriter, r *http.Reque
127131
func (ss *statusServer) getPolicyStatusHandler(w http.ResponseWriter, r *http.Request) {
128132
vars := mux.Vars(r)
129133
policy := vars["policy"]
130-
status, err := ss.ds.Get(policy)
131-
if errors.Is(err, datastore.ErrPolicyNotFound) {
132-
http.Error(w, "couldn't find requested policy", http.StatusNotFound)
134+
module, err := ss.sh.GetPolicyModule(policy)
135+
if errors.Is(err, seiface.ErrPolicyNotFound) {
136+
http.Error(w, "policy is not installed", http.StatusNotFound)
133137
return
134138
} else if err != nil {
135139
ss.l.Error(err, "error getting status")
136140
http.Error(w, "Cannot get status", http.StatusInternalServerError)
137141
return
138142
}
139143

140-
err = json.NewEncoder(w).Encode(status)
144+
cs, csErr := utils.Checksum(ss.mPath + "/" + policy + "." + module.Ext)
145+
146+
if csErr != nil {
147+
http.Error(w, "cannot find policy file in " + ss.mPath, http.StatusNotFound)
148+
return
149+
}
150+
151+
if cs != module.Checksum {
152+
http.Error(w, "Installed module " + module.Name + " does not much module file " + ss.mPath + "/" + policy + "." + module.Ext, http.StatusNotFound)
153+
return
154+
}
155+
err = json.NewEncoder(w).Encode(module)
141156
if err != nil {
142157
ss.l.Error(err, "error writing status response")
143158
http.Error(w, "Cannot get status", http.StatusInternalServerError)

pkg/semodule/interface/interface.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import (
55
"fmt"
66
)
77

8+
type PolicyModule struct {
9+
Name string
10+
Ext string
11+
Checksum string
12+
}
13+
814
// errors
915
var (
1016
// ErrHandleCreate is an error when getting a handle to semanage
@@ -23,6 +29,8 @@ var (
2329
ErrCannotInstallModule = errors.New("cannot install module")
2430
// ErrCommit is an error when committing the changes to the SELinux policy
2531
ErrCommit = errors.New("cannot commit changes to policy")
32+
// ErrPolicyNotFound is an error policy is not found in SELinux policy modules store
33+
ErrPolicyNotFound = errors.New("policy not found in SELinux store")
2634
)
2735

2836
func NewErrCannotRemoveModule(mName string) error {
@@ -42,7 +50,8 @@ func NewErrCommit(origErrVal int, msg string) error {
4250
type Handler interface {
4351
SetAutoCommit(bool)
4452
Install(string) error
45-
List() ([]string, error)
53+
List() ([]PolicyModule, error)
54+
GetPolicyModule(string) (PolicyModule, error)
4655
Remove(string) error
4756
Commit() error
4857
Close() error

pkg/semodule/policycoreutils/policycoreutils.go

+25-5
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,42 @@ func (smt *SEModulePcuHandler) Install(modulePath string) error {
4646
return nil
4747
}
4848

49-
func (smt *SEModulePcuHandler) List() ([]string, error) {
50-
out, err := runSemodule("-lfull")
49+
func (smt *SEModulePcuHandler) List() ([]seiface.PolicyModule, error) {
50+
out, err := runSemodule("-lfull", "--checksum")
5151
if err != nil {
5252
smt.logger.Error(err, "Listing policies")
5353
return nil, seiface.ErrList
5454
}
55-
modules := make([]string, 0)
55+
modules := make([]seiface.PolicyModule, 0)
5656
for _, line := range strings.Split(string(out), "\n") {
57-
module := strings.Split(line, " ")
57+
module := strings.Fields(line)
58+
if len(module) != 4 {
59+
continue
60+
}
5861
if module[0] == "350" {
59-
modules = append(modules, module[1])
62+
policyModule := seiface.PolicyModule{ module[1], module[2], module[3]}
63+
modules = append(modules, policyModule)
6064
}
6165
}
6266
return modules, nil
6367
}
6468

69+
func (smt *SEModulePcuHandler) GetPolicyModule(moduleName string) (seiface.PolicyModule, error) {
70+
modules, err := smt.List()
71+
if err != nil {
72+
smt.logger.Error(err, "Getting module checksum")
73+
return seiface.PolicyModule{}, seiface.ErrList
74+
}
75+
for _, module := range modules {
76+
// 350 module cil sha256:dadb16b11a1d298e57cbd965f5fc060b7a9263b8d6b23af7763e68ac22fb5265
77+
if module.Name == moduleName {
78+
smt.logger.Info(moduleName, "checksum", module.Checksum)
79+
return module, nil
80+
}
81+
}
82+
return seiface.PolicyModule{}, seiface.ErrPolicyNotFound
83+
}
84+
6585
func (smt *SEModulePcuHandler) Remove(modToRemove string) error {
6686
out, err := runSemodule("-X", "350", "-r", modToRemove)
6787
if err != nil {

pkg/utils/utils.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package utils
22

33
import (
4-
"crypto/sha512"
4+
"crypto/sha256"
5+
"encoding/hex"
56
"errors"
67
"fmt"
78
"io"
@@ -35,17 +36,17 @@ func PolicyNameFromPath(path string) (string, error) {
3536
}
3637

3738
// Checksum returns a checksum for a file on a given path
38-
func Checksum(path string) ([]byte, error) {
39+
func Checksum(path string) (string, error) {
3940
f, err := os.Open(path)
4041
if err != nil {
41-
return nil, fmt.Errorf("unable to calculate checksum: %w", err)
42+
return "", fmt.Errorf("unable to calculate checksum: %w", err)
4243
}
4344
defer f.Close()
4445

45-
h := sha512.New()
46+
h := sha256.New()
4647
if _, err := io.Copy(h, f); err != nil {
47-
return nil, fmt.Errorf("unable to calculate checksum: %w", err)
48+
return "", fmt.Errorf("unable to calculate checksum: %w", err)
4849
}
4950

50-
return h.Sum(nil), nil
51+
return fmt.Sprintf("sha256:%s", hex.EncodeToString(h.Sum(nil))), nil
5152
}

0 commit comments

Comments
 (0)