allow notification plugins to work on freebsd and non-root functional tests (#1253)
* random uuid for all platforms * check group writable and setgid; don't check group ownership * allow user to run plugins without changing desired user/group (set them to "")
This commit is contained in:
parent
5a15f9b39b
commit
10ce45c054
2 changed files with 53 additions and 25 deletions
1
go.sum
1
go.sum
|
@ -311,7 +311,6 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe
|
|||
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
|
||||
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
|
||||
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/protobufs"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/google/uuid"
|
||||
plugin "github.com/hashicorp/go-plugin"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
@ -253,11 +254,13 @@ func (pb *PluginBroker) loadNotificationPlugin(name string, binaryPath string) (
|
|||
return nil, err
|
||||
}
|
||||
cmd := exec.Command(binaryPath)
|
||||
cmd.SysProcAttr, err = getProcessAtr(pb.pluginProcConfig.User, pb.pluginProcConfig.Group)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "while getting process attributes")
|
||||
if pb.pluginProcConfig.User != "" || pb.pluginProcConfig.Group != "" {
|
||||
cmd.SysProcAttr, err = getProcessAttr(pb.pluginProcConfig.User, pb.pluginProcConfig.Group)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "while getting process attributes")
|
||||
}
|
||||
cmd.SysProcAttr.Credential.NoSetGroups = true
|
||||
}
|
||||
cmd.SysProcAttr.Credential.NoSetGroups = true
|
||||
pb.pluginMap[name] = &NotifierPlugin{}
|
||||
l := log.New()
|
||||
err = types.ConfigureLogger(l)
|
||||
|
@ -288,6 +291,7 @@ func (pb *PluginBroker) loadNotificationPlugin(name string, binaryPath string) (
|
|||
}
|
||||
|
||||
func (pb *PluginBroker) pushNotificationsToPlugin(pluginName string, alerts []*models.Alert) error {
|
||||
log.WithField("plugin", pluginName).Debug("pushing alerts to plugin")
|
||||
if len(alerts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
@ -372,18 +376,27 @@ func pluginIsValid(path string) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "while getting current user")
|
||||
}
|
||||
procAttr, err := getProcessAtr(currentUser.Username, currentUser.Username)
|
||||
currentUID, err := getUID(currentUser.Username)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "while getting process attributes")
|
||||
return errors.Wrap(err, "while looking up the current uid")
|
||||
}
|
||||
stat := details.Sys().(*syscall.Stat_t)
|
||||
if stat.Uid != procAttr.Credential.Uid || stat.Gid != procAttr.Credential.Gid {
|
||||
return fmt.Errorf("plugin at %s is not owned by %s user and group", path, currentUser.Username)
|
||||
if stat.Uid != currentUID {
|
||||
return fmt.Errorf("plugin at %s is not owned by user '%s'", path, currentUser.Username)
|
||||
}
|
||||
|
||||
if (int(details.Mode()) & 2) != 0 {
|
||||
mode := details.Mode()
|
||||
perm := uint32(mode)
|
||||
|
||||
if (perm & 00002) != 0 {
|
||||
return fmt.Errorf("plugin at %s is world writable, world writable plugins are invalid", path)
|
||||
}
|
||||
if (perm & 00020) != 0 {
|
||||
return fmt.Errorf("plugin at %s is group writable, group writable plugins are invalid", path)
|
||||
}
|
||||
if (mode & os.ModeSetgid) != 0 {
|
||||
return fmt.Errorf("plugin at %s has setgid permission, which is not allowed", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -412,43 +425,59 @@ func getPluginTypeAndSubtypeFromPath(path string) (string, string, error) {
|
|||
return strings.Join(parts[:len(parts)-1], "-"), parts[len(parts)-1], nil
|
||||
}
|
||||
|
||||
func getProcessAtr(username string, groupname string) (*syscall.SysProcAttr, error) {
|
||||
func getUID(username string) (uint32, error) {
|
||||
u, err := user.Lookup(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g, err := user.LookupGroup(groupname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, err
|
||||
}
|
||||
uid, err := strconv.ParseInt(u.Uid, 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, err
|
||||
}
|
||||
if uid < 0 || uid > math.MaxInt32 {
|
||||
return nil, fmt.Errorf("out of bound uid")
|
||||
return 0, fmt.Errorf("out of bound uid")
|
||||
}
|
||||
return uint32(uid), nil
|
||||
}
|
||||
|
||||
func getGID(groupname string) (uint32, error) {
|
||||
g, err := user.LookupGroup(groupname)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
gid, err := strconv.ParseInt(g.Gid, 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, err
|
||||
}
|
||||
if gid < 0 || gid > math.MaxInt32 {
|
||||
return nil, fmt.Errorf("out of bound gid")
|
||||
return 0, fmt.Errorf("out of bound gid")
|
||||
}
|
||||
return uint32(gid), nil
|
||||
}
|
||||
|
||||
func getProcessAttr(username string, groupname string) (*syscall.SysProcAttr, error) {
|
||||
uid, err := getUID(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gid, err := getGID(groupname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &syscall.SysProcAttr{
|
||||
Credential: &syscall.Credential{
|
||||
Uid: uint32(uid),
|
||||
Gid: uint32(gid),
|
||||
Uid: uid,
|
||||
Gid: gid,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getUUID() (string, error) {
|
||||
if d, err := os.ReadFile("/proc/sys/kernel/random/uuid"); err != nil {
|
||||
uuidv4, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return string(d), nil
|
||||
}
|
||||
return uuidv4.String(), nil
|
||||
}
|
||||
|
||||
func getHandshake() (plugin.HandshakeConfig, error) {
|
||||
|
|
Loading…
Reference in a new issue