|
@@ -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) {
|