Added per-process (ephemeral) rule support.

(proc coroner now has support for multiple callbacks)
shw_dev
shw 8 years ago
parent af874c7395
commit 0f2b2413ea

@ -65,8 +65,7 @@ func newDbusServer() (*dbusServer, error) {
func (ds *dbusServer) RequestPrompt(application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, func (ds *dbusServer) RequestPrompt(application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32,
optstring string, expanded, expert bool, action int32) (int32, string, *dbus.Error) { optstring string, expanded, expert bool, action int32) (int32, string, *dbus.Error) {
log.Printf("REALLY GOT IT!") log.Printf("request prompt: app = %s, icon = %s, path = %s, address = %s, action = %v\n", application, icon, path, address, action)
log.Printf("app = %s, icon = %s, path = %s, address = %s, action = %v\n", application, icon, path, address, action)
decision := addRequest(nil, path, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, optstring) decision := addRequest(nil, path, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, optstring)
log.Print("Waiting on decision...") log.Print("Waiting on decision...")
decision.Cond.L.Lock() decision.Cond.L.Lock()

@ -513,7 +513,7 @@ func createCurrentRule() (ruleColumns, error) {
var err error = nil var err error = nil
if radioProcess.GetActive() { if radioProcess.GetActive() {
return rule, errors.New("Process scope is unsupported at the moment") rule.Scope = int(sgfw.APPLY_PROCESS)
} else if radioParent.GetActive() { } else if radioParent.GetActive() {
return rule, errors.New("Parent process scope is unsupported at the moment") return rule, errors.New("Parent process scope is unsupported at the moment")
} else if radioSession.GetActive() { } else if radioSession.GetActive() {
@ -612,7 +612,6 @@ func getSelectedRule() (ruleColumns, int, error) {
} }
rows := sel.GetSelectedRows(globalLS) rows := sel.GetSelectedRows(globalLS)
fmt.Println("RETURNED ROWS: ", rows.Length())
if rows.Length() <= 0 { if rows.Length() <= 0 {
return rule, -1, errors.New("No selection was made") return rule, -1, errors.New("No selection was made")
@ -814,7 +813,6 @@ func main() {
radioParent = get_radiobutton(radioOnce, "Parent Process", false) radioParent = get_radiobutton(radioOnce, "Parent Process", false)
radioSession = get_radiobutton(radioOnce, "Session", false) radioSession = get_radiobutton(radioOnce, "Session", false)
radioPermanent = get_radiobutton(radioOnce, "Permanent", false) radioPermanent = get_radiobutton(radioOnce, "Permanent", false)
radioProcess.SetSensitive(false)
radioParent.SetSensitive(false) radioParent.SetSensitive(false)
hbox.PackStart(lbl, false, false, 10) hbox.PackStart(lbl, false, false, 10)
hbox.PackStart(radioOnce, false, false, 5) hbox.PackStart(radioOnce, false, false, 5)
@ -948,6 +946,7 @@ func main() {
editPort.SetText(strconv.Itoa(seldata.Port)) editPort.SetText(strconv.Itoa(seldata.Port))
radioOnce.SetActive(true) radioOnce.SetActive(true)
radioProcess.SetActive(false) radioProcess.SetActive(false)
radioProcess.SetSensitive(seldata.Pid > 0)
radioParent.SetActive(false) radioParent.SetActive(false)
radioSession.SetActive(false) radioSession.SetActive(false)
radioPermanent.SetActive(false) radioPermanent.SetActive(false)
@ -971,6 +970,7 @@ func main() {
chkUser.SetActive(false) chkUser.SetActive(false)
chkGroup.SetActive(false) chkGroup.SetActive(false)
return return
}) })

@ -76,7 +76,7 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow" id="swRulesSystem"> <object class="GtkScrolledWindow" id="swRulesProcess">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
@ -93,7 +93,7 @@
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="label" translatable="yes">System</property> <property name="label" translatable="yes">Process</property>
</object> </object>
<packing> <packing>
<property name="position">2</property> <property name="position">2</property>
@ -101,6 +101,32 @@
<property name="tab_fill">False</property> <property name="tab_fill">False</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkScrolledWindow" id="swRulesSystem">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
</object>
<packing>
<property name="position">3</property>
<property name="tab_expand">True</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">System</property>
</object>
<packing>
<property name="position">3</property>
<property name="tab_expand">True</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="name">page0</property> <property name="name">page0</property>

@ -86,7 +86,7 @@ func (*defDialog) String() string {
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow" id="swRulesSystem"> <object class="GtkScrolledWindow" id="swRulesProcess">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
@ -103,7 +103,7 @@ func (*defDialog) String() string {
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="label" translatable="yes">System</property> <property name="label" translatable="yes">Process</property>
</object> </object>
<packing> <packing>
<property name="position">2</property> <property name="position">2</property>
@ -111,6 +111,32 @@ func (*defDialog) String() string {
<property name="tab_fill">False</property> <property name="tab_fill">False</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkScrolledWindow" id="swRulesSystem">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
</object>
<packing>
<property name="position">3</property>
<property name="tab_expand">True</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">System</property>
</object>
<packing>
<property name="position">3</property>
<property name="tab_expand">True</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="name">page0</property> <property name="name">page0</property>
@ -272,6 +298,7 @@ func (*defDialog) String() string {
<items> <items>
<item id="FOREVER" translatable="yes">Forever</item> <item id="FOREVER" translatable="yes">Forever</item>
<item id="SESSION" translatable="yes">Session</item> <item id="SESSION" translatable="yes">Session</item>
<item id="PROCESS" translatable="yes">Process</item>
<item id="ONCE" translatable="yes">Once</item> <item id="ONCE" translatable="yes">Once</item>
</items> </items>
<signal name="changed" handler="on_action_combo_changed" swapped="no"/> <signal name="changed" handler="on_action_combo_changed" swapped="no"/>

@ -15,6 +15,7 @@ var fwswin *gtk.Window = nil
var fwsbuilder *builder = nil var fwsbuilder *builder = nil
var swRulesPermanent *gtk.ScrolledWindow = nil var swRulesPermanent *gtk.ScrolledWindow = nil
var swRulesSession *gtk.ScrolledWindow = nil var swRulesSession *gtk.ScrolledWindow = nil
var swRulesProcess *gtk.ScrolledWindow = nil
var swRulesSystem *gtk.ScrolledWindow = nil var swRulesSystem *gtk.ScrolledWindow = nil
func failDialog(parent *gtk.Window, format string, args ...interface{}) { func failDialog(parent *gtk.Window, format string, args ...interface{}) {
@ -38,6 +39,7 @@ var repopMutex = &sync.Mutex{}
func repopulateWin() { func repopulateWin() {
fmt.Println("Refreshing firewall rule list.") fmt.Println("Refreshing firewall rule list.")
repopMutex.Lock() repopMutex.Lock()
defer repopMutex.Unlock()
win := fwswin win := fwswin
dbus, err := newDbusObject() dbus, err := newDbusObject()
@ -57,9 +59,15 @@ func repopulateWin() {
} }
swRulesSession.Remove(child) swRulesSession.Remove(child)
child, err = swRulesProcess.GetChild()
if err != nil {
failDialog(win, "Unable to clear out process rules list display: %v", err)
}
swRulesProcess.Remove(child)
child, err = swRulesSystem.GetChild() child, err = swRulesSystem.GetChild()
if err != nil { if err != nil {
failDialog(win, "Unable to clear out session rules list display: %v", err) failDialog(win, "Unable to clear out system rules list display: %v", err)
} }
swRulesSystem.Remove(child) swRulesSystem.Remove(child)
@ -69,10 +77,12 @@ func repopulateWin() {
boxSession, _ := gtk.ListBoxNew() boxSession, _ := gtk.ListBoxNew()
swRulesSession.Add(boxSession) swRulesSession.Add(boxSession)
boxProcess, _ := gtk.ListBoxNew()
swRulesProcess.Add(boxProcess)
boxSystem, _ := gtk.ListBoxNew() boxSystem, _ := gtk.ListBoxNew()
swRulesSystem.Add(boxSystem) swRulesSystem.Add(boxSystem)
rlPermanent := newRuleList(dbus, win, boxPermanent) rlPermanent := newRuleList(dbus, win, boxPermanent)
if _, err := dbus.isEnabled(); err != nil { if _, err := dbus.isEnabled(); err != nil {
failDialog(win, "Unable is connect to firewall daemon. Is it running?") failDialog(win, "Unable is connect to firewall daemon. Is it running?")
@ -85,6 +95,12 @@ func repopulateWin() {
} }
rlSession.loadRules(sgfw.RULE_MODE_SESSION) rlSession.loadRules(sgfw.RULE_MODE_SESSION)
rlProcess := newRuleList(dbus, win, boxProcess)
if _, err := dbus.isEnabled(); err != nil {
failDialog(win, "Unable is connect to firewall daemon. Is it running?")
}
rlProcess.loadRules(sgfw.RULE_MODE_PROCESS)
rlSystem := newRuleList(dbus, win, boxSystem) rlSystem := newRuleList(dbus, win, boxSystem)
if _, err := dbus.isEnabled(); err != nil { if _, err := dbus.isEnabled(); err != nil {
failDialog(win, "Unable is connect to firewall daemon. Is it running?") failDialog(win, "Unable is connect to firewall daemon. Is it running?")
@ -94,7 +110,6 @@ func repopulateWin() {
loadConfig(win, fwsbuilder, dbus) loadConfig(win, fwsbuilder, dbus)
// app.AddWindow(win) // app.AddWindow(win)
win.ShowAll() win.ShowAll()
repopMutex.Unlock()
} }
func populateWin(app *gtk.Application, win *gtk.Window) { func populateWin(app *gtk.Application, win *gtk.Window) {
@ -104,6 +119,7 @@ func populateWin(app *gtk.Application, win *gtk.Window) {
"window", &win, "window", &win,
"swRulesPermanent", &swRulesPermanent, "swRulesPermanent", &swRulesPermanent,
"swRulesSession", &swRulesSession, "swRulesSession", &swRulesSession,
"swRulesProcess", &swRulesProcess,
"swRulesSystem", &swRulesSystem, "swRulesSystem", &swRulesSystem,
) )
//win.SetIconName("security-high-symbolic") //win.SetIconName("security-high-symbolic")
@ -115,6 +131,9 @@ func populateWin(app *gtk.Application, win *gtk.Window) {
boxSession, _ := gtk.ListBoxNew() boxSession, _ := gtk.ListBoxNew()
swRulesSession.Add(boxSession) swRulesSession.Add(boxSession)
boxProcess, _ := gtk.ListBoxNew()
swRulesProcess.Add(boxProcess)
boxSystem, _ := gtk.ListBoxNew() boxSystem, _ := gtk.ListBoxNew()
swRulesSystem.Add(boxSystem) swRulesSystem.Add(boxSystem)
@ -135,6 +154,12 @@ func populateWin(app *gtk.Application, win *gtk.Window) {
} }
rlSession.loadRules(sgfw.RULE_MODE_SESSION) rlSession.loadRules(sgfw.RULE_MODE_SESSION)
rlProcess := newRuleList(dbus, win, boxProcess)
if _, err := dbus.isEnabled(); err != nil {
failDialog(win, "Unable is connect to firewall daemon. Is it running?")
}
rlProcess.loadRules(sgfw.RULE_MODE_PROCESS)
rlSystem := newRuleList(dbus, win, boxSystem) rlSystem := newRuleList(dbus, win, boxSystem)
if _, err := dbus.isEnabled(); err != nil { if _, err := dbus.isEnabled(); err != nil {
failDialog(win, "Unable is connect to firewall daemon. Is it running?") failDialog(win, "Unable is connect to firewall daemon. Is it running?")

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"strings" "strings"
"strconv"
"github.com/subgraph/fw-daemon/sgfw" "github.com/subgraph/fw-daemon/sgfw"
@ -113,7 +114,12 @@ func createWidget(rule *sgfw.DbusRule) *ruleRow {
} }
func (rr *ruleRow) update() { func (rr *ruleRow) update() {
rr.gtkLabelApp.SetText(rr.rule.App) if rr.rule.Mode == uint16(sgfw.RULE_MODE_PROCESS) {
appstr := "(" + strconv.Itoa(int(rr.rule.Pid)) + ") " + rr.rule.App
rr.gtkLabelApp.SetText(appstr)
} else {
rr.gtkLabelApp.SetText(rr.rule.App)
}
rr.gtkLabelApp.SetTooltipText(rr.rule.Path) rr.gtkLabelApp.SetTooltipText(rr.rule.Path)
rr.gtkLabelVerb.SetText(getVerbText(rr.rule)) rr.gtkLabelVerb.SetText(getVerbText(rr.rule))
if (rr.rule.Proto == "tcp") { if (rr.rule.Proto == "tcp") {

@ -12,7 +12,8 @@ const Tweener = imports.ui.tweener;
const RuleScope = { const RuleScope = {
APPLY_ONCE: 0, APPLY_ONCE: 0,
APPLY_SESSION: 1, APPLY_SESSION: 1,
APPLY_FOREVER: 2, APPLY_PROCESS: 2,
APPLY_FOREVER: 3,
}; };
const DetailSection = new Lang.Class({ const DetailSection = new Lang.Class({
@ -129,9 +130,13 @@ Signals.addSignalMethods(OptionListItem.prototype);
const OptionList = new Lang.Class({ const OptionList = new Lang.Class({
Name: 'OptionList', Name: 'OptionList',
_init: function() { _init: function(pid_known) {
this.actor = new St.BoxLayout({vertical: true, style_class: 'fw-option-list'}); this.actor = new St.BoxLayout({vertical: true, style_class: 'fw-option-list'});
this.buttonGroup = new ButtonGroup("Forever", "Session", "Once"); if (pid_known) {
this.buttonGroup = new ButtonGroup("Forever", "Session", "Once", "PID");
} else {
this.buttonGroup = new ButtonGroup("Forever", "Session", "Once");
}
this.actor.add_child(this.buttonGroup.actor); this.actor.add_child(this.buttonGroup.actor);
this.items = []; this.items = [];
this._selected; this._selected;
@ -188,6 +193,8 @@ const OptionList = new Lang.Class({
return RuleScope.APPLY_SESSION; return RuleScope.APPLY_SESSION;
case 2: case 2:
return RuleScope.APPLY_ONCE; return RuleScope.APPLY_ONCE;
case 3:
return RuleScope.APPLY_PROCESS;
default: default:
log("unexpected scope value "+ this.buttonGroup._selected); log("unexpected scope value "+ this.buttonGroup._selected);
return RuleScope.APPLY_SESSION; return RuleScope.APPLY_SESSION;
@ -196,6 +203,8 @@ const OptionList = new Lang.Class({
scopeToIdx: function(scope) { scopeToIdx: function(scope) {
switch (scope) { switch (scope) {
case RuleScope.APPLY_PROCESS:
return 3;
case RuleScope.APPLY_ONCE: case RuleScope.APPLY_ONCE:
return 2; return 2;
case RuleScope.APPLY_SESSION: case RuleScope.APPLY_SESSION:
@ -413,7 +422,7 @@ const PromptDialog = new Lang.Class({
Name: 'PromptDialog', Name: 'PromptDialog',
Extends: ModalDialog.ModalDialog, Extends: ModalDialog.ModalDialog,
_init: function(invocation) { _init: function(invocation, pid_known) {
this.parent({ styleClass: 'fw-prompt-dialog' }); this.parent({ styleClass: 'fw-prompt-dialog' });
this._invocation = invocation; this._invocation = invocation;
this.header = new PromptDialogHeader(); this.header = new PromptDialogHeader();
@ -426,7 +435,7 @@ const PromptDialog = new Lang.Class({
this.info = new DetailSection(); this.info = new DetailSection();
box.add_child(this.info.actor); box.add_child(this.info.actor);
this.optionList = new OptionList(); this.optionList = new OptionList(pid_known);
box.add_child(this.optionList.actor); box.add_child(this.optionList.actor);
this.optionList.addOptions([ this.optionList.addOptions([
"Only PORT AND ADDRESS", "Only PORT AND ADDRESS",

@ -94,7 +94,7 @@ const FirewallPromptHandler = new Lang.Class({
RequestPromptAsync: function(params, invocation) { RequestPromptAsync: function(params, invocation) {
let [app, icon, path, address, port, ip, origin, proto, uid, gid, user, group, pid, optstring, expanded, expert, action] = params; let [app, icon, path, address, port, ip, origin, proto, uid, gid, user, group, pid, optstring, expanded, expert, action] = params;
// this._closeDialog(); // this._closeDialog();
this._dialog = new Dialog.PromptDialog(invocation); this._dialog = new Dialog.PromptDialog(invocation, (pid >= 0));
this._invocation = invocation; this._invocation = invocation;
this._dialog.update(app, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, expanded, expert, action); this._dialog.update(app, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, expanded, expert, action);
this._dialog.open(); this._dialog.open();

@ -18,9 +18,17 @@ type WatchProcess struct {
Stime int Stime int
} }
type CallbackEntry struct {
fn procCB
param interface{}
}
type procCB func(int, interface{}) type procCB func(int, interface{})
var Callbacks []CallbackEntry
var pmutex = &sync.Mutex{} var pmutex = &sync.Mutex{}
var pidMap map[int]WatchProcess = make(map[int]WatchProcess) var pidMap map[int]WatchProcess = make(map[int]WatchProcess)
@ -53,6 +61,11 @@ func UnmonitorProcess(pid int) {
return return
} }
func AddCallback(cbfunc procCB, param interface{}) {
cbe := CallbackEntry{cbfunc, param}
Callbacks = append(Callbacks, cbe)
}
func MonitorThread(cbfunc procCB, param interface{}) { func MonitorThread(cbfunc procCB, param interface{}) {
for { for {
/* if len(pidMap) == 0 { /* if len(pidMap) == 0 {
@ -71,12 +84,15 @@ func MonitorThread(cbfunc procCB, param interface{}) {
if cbfunc != nil { if cbfunc != nil {
cbfunc(pkey, param) cbfunc(pkey, param)
} }
for i := 0; i < len(Callbacks); i++ {
Callbacks[i].fn(pkey, Callbacks[i].param)
}
continue continue
} }
} }
time.Sleep(2 * time.Second) time.Sleep(1 * time.Second)
} }
} }

@ -31,18 +31,21 @@ var RuleActionValue = map[string]RuleAction{
type RuleMode uint16 type RuleMode uint16
const ( const (
RULE_MODE_SESSION RuleMode = iota RULE_MODE_SESSION RuleMode = iota
RULE_MODE_PROCESS
RULE_MODE_PERMANENT RULE_MODE_PERMANENT
RULE_MODE_SYSTEM RULE_MODE_SYSTEM
) )
// RuleModeString is used to get a rule mode string from its id // RuleModeString is used to get a rule mode string from its id
var RuleModeString = map[RuleMode]string{ var RuleModeString = map[RuleMode]string{
RULE_MODE_SESSION: "SESSION", RULE_MODE_SESSION: "SESSION",
RULE_MODE_PROCESS: "PROCESS",
RULE_MODE_PERMANENT: "PERMANENT", RULE_MODE_PERMANENT: "PERMANENT",
RULE_MODE_SYSTEM: "SYSTEM", RULE_MODE_SYSTEM: "SYSTEM",
} }
// RuleModeValue converts a mode string to its id // RuleModeValue converts a mode string to its id
var RuleModeValue = map[string]RuleMode{ var RuleModeValue = map[string]RuleMode{
RuleModeString[RULE_MODE_SESSION]: RULE_MODE_SESSION, RuleModeString[RULE_MODE_SESSION]: RULE_MODE_SESSION,
RuleModeString[RULE_MODE_PROCESS]: RULE_MODE_PROCESS,
RuleModeString[RULE_MODE_PERMANENT]: RULE_MODE_PERMANENT, RuleModeString[RULE_MODE_PERMANENT]: RULE_MODE_PERMANENT,
RuleModeString[RULE_MODE_SYSTEM]: RULE_MODE_SYSTEM, RuleModeString[RULE_MODE_SYSTEM]: RULE_MODE_SYSTEM,
} }
@ -52,18 +55,21 @@ type FilterScope uint16
const ( const (
APPLY_ONCE FilterScope = iota APPLY_ONCE FilterScope = iota
APPLY_SESSION APPLY_SESSION
APPLY_PROCESS
APPLY_FOREVER APPLY_FOREVER
) )
// FilterScopeString converts a filter scope ID to its string // FilterScopeString converts a filter scope ID to its string
var FilterScopeString = map[FilterScope]string{ var FilterScopeString = map[FilterScope]string{
APPLY_ONCE: "ONCE", APPLY_ONCE: "ONCE",
APPLY_SESSION: "SESSION", APPLY_SESSION: "SESSION",
APPLY_PROCESS: "PROCESS",
APPLY_FOREVER: "FOREVER", APPLY_FOREVER: "FOREVER",
} }
// FilterScopeString converts a filter scope string to its ID // FilterScopeString converts a filter scope string to its ID
var FilterScopeValue = map[string]FilterScope{ var FilterScopeValue = map[string]FilterScope{
FilterScopeString[APPLY_ONCE]: APPLY_ONCE, FilterScopeString[APPLY_ONCE]: APPLY_ONCE,
FilterScopeString[APPLY_SESSION]: APPLY_SESSION, FilterScopeString[APPLY_SESSION]: APPLY_SESSION,
FilterScopeString[APPLY_PROCESS]: APPLY_PROCESS,
FilterScopeString[APPLY_FOREVER]: APPLY_FOREVER, FilterScopeString[APPLY_FOREVER]: APPLY_FOREVER,
} }
// GetFilterScopeString is used to safely return a filter scope string // GetFilterScopeString is used to safely return a filter scope string
@ -108,6 +114,7 @@ type DbusRule struct {
Net string Net string
Origin string Origin string
Proto string Proto string
Pid uint32
Privs string Privs string
App string App string
Path string Path string
@ -116,8 +123,8 @@ type DbusRule struct {
Mode uint16 Mode uint16
} }
const ( /*const (
OZ_FWRULE_WHITELIST = iota OZ_FWRULE_WHITELIST = iota
OZ_FWRULE_BLACKLIST OZ_FWRULE_BLACKLIST
OZ_FWRULE_NONE OZ_FWRULE_NONE
) ) */

@ -8,6 +8,7 @@ import (
"github.com/godbus/dbus" "github.com/godbus/dbus"
"github.com/godbus/dbus/introspect" "github.com/godbus/dbus/introspect"
"github.com/op/go-logging" "github.com/op/go-logging"
"github.com/subgraph/fw-daemon/proc-coroner"
) )
const introspectXML = ` const introspectXML = `
@ -68,6 +69,31 @@ type dbusServer struct {
prompter *prompter prompter *prompter
} }
func DbusProcDeathCB(pid int, param interface{}) {
ds := param.(*dbusServer)
ds.fw.lock.Lock()
defer ds.fw.lock.Unlock()
done, updated := false, false
for !done {
done = true
for _, p := range ds.fw.policies {
for r := 0; r < len(p.rules); r++ {
if p.rules[r].pid == pid && p.rules[r].mode == RULE_MODE_PROCESS {
p.rules = append(p.rules[:r], p.rules[r+1:]...)
done = false
updated = true
log.Notice("Removed per-process firewall rule for PID: ", pid)
break
}
}
}
}
if updated {
dbusp.alertRule("Firewall removed on process death")
}
}
func newDbusServer() (*dbusServer, error) { func newDbusServer() (*dbusServer, error) {
conn, err := dbus.SystemBus() conn, err := dbus.SystemBus()
if err != nil { if err != nil {
@ -92,6 +118,7 @@ func newDbusServer() (*dbusServer, error) {
ds.conn = conn ds.conn = conn
ds.prompter = newPrompter(conn) ds.prompter = newPrompter(conn)
pcoroner.AddCallback(DbusProcDeathCB, ds)
return ds, nil return ds, nil
} }
@ -132,6 +159,7 @@ func createDbusRule(r *Rule) DbusRule {
Net: netstr, Net: netstr,
Origin: ostr, Origin: ostr,
Proto: r.proto, Proto: r.proto,
Pid: uint32(r.pid),
Privs: pstr, Privs: pstr,
App: path.Base(r.policy.path), App: path.Base(r.policy.path),
Path: r.policy.path, Path: r.policy.path,
@ -191,6 +219,8 @@ func (ds *dbusServer) UpdateRule(rule DbusRule) *dbus.Error {
r.rtype = RuleAction(rule.Verb) r.rtype = RuleAction(rule.Verb)
} }
r.hostname = tmp.hostname r.hostname = tmp.hostname
r.proto = tmp.proto
r.pid = tmp.pid
r.addr = tmp.addr r.addr = tmp.addr
r.port = tmp.port r.port = tmp.port
r.mode = RuleMode(rule.Mode) r.mode = RuleMode(rule.Mode)

@ -14,9 +14,6 @@ import (
"github.com/subgraph/fw-daemon/proc-coroner" "github.com/subgraph/fw-daemon/proc-coroner"
) )
var monitoring = false
var mlock = sync.Mutex{}
type dnsEntry struct { type dnsEntry struct {
name string name string
ttl uint32 ttl uint32
@ -96,8 +93,7 @@ func (dc *dnsCache) processDNS(pkt *nfqueue.NFQPacket) {
} }
} */ } */
func procDeathCallback(pid int, param interface{}) { func procDeathCallbackDNS(pid int, param interface{}) {
// log.Warning("XXX: IN CALLBACK for pid: ", pid, " / param = ", param)
if pid != 0 { if pid != 0 {
cache := param.(*dnsCache) cache := param.(*dnsCache)
@ -148,15 +144,6 @@ func (dc *dnsCache) processRecordAddress(name string, answers []dnsRR, pid int)
if pid > 0 { if pid > 0 {
log.Warning("Adding process to be monitored by DNS cache: ", pid) log.Warning("Adding process to be monitored by DNS cache: ", pid)
if !monitoring {
mlock.Lock()
if !monitoring {
monitoring = true
// go checker(dc)
go pcoroner.MonitorThread(procDeathCallback, dc)
}
mlock.Unlock()
}
pcoroner.MonitorProcess(pid) pcoroner.MonitorProcess(pid)
} }
if !FirewallConfig.LogRedact { if !FirewallConfig.LogRedact {

@ -298,6 +298,7 @@ func (p *Policy) processNewRule(r *Rule, scope FilterScope) bool {
func (p *Policy) parseRule(s string, add bool) (*Rule, error) { func (p *Policy) parseRule(s string, add bool) (*Rule, error) {
log.Noticef("XXX: attempt to parse rule: |%s|\n", s) log.Noticef("XXX: attempt to parse rule: |%s|\n", s)
r := new(Rule) r := new(Rule)
r.pid = -1
r.mode = RULE_MODE_PERMANENT r.mode = RULE_MODE_PERMANENT
r.policy = p r.policy = p
if !r.parse(s) { if !r.parse(s) {

@ -8,6 +8,7 @@ import (
"sync" "sync"
"github.com/godbus/dbus" "github.com/godbus/dbus"
"github.com/subgraph/fw-daemon/proc-coroner"
) )
@ -177,6 +178,10 @@ func (p *prompter) processConnection(pc pendingConnection) {
fscope := FilterScope(scope) fscope := FilterScope(scope)
if fscope == APPLY_SESSION { if fscope == APPLY_SESSION {
r.mode = RULE_MODE_SESSION r.mode = RULE_MODE_SESSION
} else if fscope == APPLY_PROCESS {
r.mode = RULE_MODE_PROCESS
r.pid = pc.procInfo().Pid
pcoroner.MonitorProcess(r.pid)
} }
if !policy.processNewRule(r, fscope) { if !policy.processNewRule(r, fscope) {
p.lock.Lock() p.lock.Lock()

@ -27,6 +27,7 @@ type Rule struct {
mode RuleMode mode RuleMode
rtype RuleAction rtype RuleAction
proto string proto string
pid int
hostname string hostname string
network *net.IPNet network *net.IPNet
addr net.IP addr net.IP
@ -146,7 +147,7 @@ func (rl *RuleList) filter(pkt *nfqueue.NFQPacket, src, dst net.IP, dstPort uint
result := FILTER_PROMPT result := FILTER_PROMPT
sandboxed := strings.HasPrefix(optstr, "Sandbox") sandboxed := strings.HasPrefix(optstr, "Sandbox")
for _, r := range *rl { for _, r := range *rl {
log.Notice("------------ trying match of src ", src, " against: ", r, " | ", r.saddr, " / optstr = ", optstr) log.Notice("------------ trying match of src ", src, " against: ", r, " | ", r.saddr, " / optstr = ", optstr, "; pid ", pinfo.Pid, " vs rule pid ", r.pid)
if r.saddr == nil && src != nil && sandboxed { if r.saddr == nil && src != nil && sandboxed {
log.Notice("! Skipping comparison against incompatible rule types: rule src = ", r.saddr, " / packet src = ", src) log.Notice("! Skipping comparison against incompatible rule types: rule src = ", r.saddr, " / packet src = ", src)
continue continue
@ -154,6 +155,10 @@ log.Notice("! Skipping comparison against incompatible rule types: rule src = ",
log.Notice("! Skipping comparison of mismatching source ips") log.Notice("! Skipping comparison of mismatching source ips")
continue continue
} }
if r.pid >= 0 && r.pid != pinfo.Pid {
//log.Notice("! Skipping comparison of mismatching PIDs")
continue
}
if r.match(src, dst, dstPort, hostname, getNFQProto(pkt), pinfo.UID, pinfo.GID, uidToUser(pinfo.UID), gidToGroup(pinfo.GID)) { if r.match(src, dst, dstPort, hostname, getNFQProto(pkt), pinfo.UID, pinfo.GID, uidToUser(pinfo.UID), gidToGroup(pinfo.GID)) {
log.Notice("+ MATCH SUCCEEDED") log.Notice("+ MATCH SUCCEEDED")
dstStr := dst.String() dstStr := dst.String()

@ -16,6 +16,7 @@ import (
nfqueue "github.com/subgraph/go-nfnetlink/nfqueue" nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
// "github.com/subgraph/go-nfnetlink" // "github.com/subgraph/go-nfnetlink"
"github.com/subgraph/go-procsnitch" "github.com/subgraph/go-procsnitch"
"github.com/subgraph/fw-daemon/proc-coroner"
"github.com/google/gopacket" "github.com/google/gopacket"
"github.com/google/gopacket/layers" "github.com/google/gopacket/layers"
) )
@ -227,6 +228,7 @@ func Main() {
stopChan: make(chan bool, 0), stopChan: make(chan bool, 0),
} }
ds.fw = fw ds.fw = fw
go pcoroner.MonitorThread(procDeathCallbackDNS, fw.dns)
fw.loadRules() fw.loadRules()

Loading…
Cancel
Save