fireflier firewall userspace program doing userspace packet filtering
hi, this message is probably directed at catching rusty's attention (hi rusty) but anyone who is able to help, assistance much appreciated. please reply cc as i ain't subscribing to lkml!
background:
i find only _one_ firewall program [in debian] that is capable of doing firewall on-demand "popup" rule creation and packet filtering, it's called "fireflier".
this also the _only_ program that i know of that also does user-space packet filtering.
in other words, not only can fireflier allow you to create rules as-and-when packets come in or out (and they are queued/blocked until they are "approved") but also it allows you to create firewall rules on a PER-PROGRAM basis.
which is very cool, and i don't see _any_ other firewall program doing that - for linux.
[if anyone knows of any such MATURE AND STABLE userspace firewall
programs with the same capability as fireflier please do let me know because the questions stop]
with that background in mind, here is the problem:
fireflier's "per-program" userspace packet filtering is very basic: it contains NO state-based filtering. none. zip. nada.
therefore, when a program dies, the "pid" of the program, which is part of the rule, becomes lost, such that FIN ACK and RST packets get thrown to the queue... and consequently to the user, because you can be certain that there will not have been a RST or FIN ACK firewall rule created!!!
with the background and the problem in mind, here is the question:
is it possible to leverage - and i mean without cut/pasting large parts of kernel-space code into fireflier-in-userspace - the EXISTING kernel's iptables functionality in some way, such that per-program packet filtering may be performed?
i don't actually care whether code is moved into kernel (100 lines), i don't care if code is added in userspace (100 lines). what i am looking for is a QUICK way to, say... leverage an existing API in the kernel, add one extra field (a pid) to the kernel as a hack, add a callback and a void* to the ip tracking structures as an "extra packet check" as a hack, that sort of thing, where the userspace callback gets its original void* plus the packet handed to it.
the last thing i want is to cut/paste several man-years of code from the kernel to user-space - things like ip_conntrack.
ultimate aim:
to be able to "enhance" existing iptables firewall rule checking rather than to be backed into a corner of "replacing" existing functionality.... just because of one extra check [the pid]
l.
Signature · 7 lines
-- Truth, honesty and respect are rare commodities that all spring from the same well: Love. If you love yourself and everyone and everything around you, funnily and coincidentally enough, life gets a lot better. -- <a href="http://lkcl.net"> lkcl.net </a> <br /> <a href="mailto:[email protected]"> [email protected] </a> <br />
regarding this issue, i have done some exploration and found that ipt_owner is capable of registering by pid.
therefore, the naive approach considered was to have fireflier "vet" rules via its userspace rules dynamically creating per-pid _new_ and _real_ rules (based on the template of options specified from the corresponding userspace rule) but of course with the ipt_owner "pid" set.
this would at first glance solve the "INCOMING" problem which i understand the present ipt_owner code to be suffering from.
anyway - this approach is insufficient and fraught with difficulties, not least involving purging the queue of existing packets that _would_ match the newly created rule, but it's too late, they're already in the queue.
etc.
so, what i would like to consider doing is to modify the ipt_owner module to include the full pathname of the binary it is supposed to vet.
i don't give a rat's monkeybutt about "oo, yuk, that's disgusting to do that in the kernel" or "that would _so_ slow network traffic down": i don't care: this is going in an selinux system where the performance hit of selinux has already been accepted, so a couple more percentage performance hit i really don't give a stuff.
so, my question, therefore, is:
what should i record in a modified version of ipt_owner in order to "vet" packets on a per-executable basis?
should i consider recording the inode of the program's binary?
should i consider recording the _name_ of the program?
if i record the inode number, what example code should i examine in order to DoTheRightThing of getting from process-pid to inode/program?
for example, i notice in ipt_owner.c that match_pid() callsfind_task_by_pid(). okkkaaay... so... and then in fs/proc/base.c'sproc_exe_link(), i see that get_task_mm() is called to get
something called an mm_struct. and theeeennn... dget is called
on _that_, and _then_ in struct dentry, there's something called a d_inode, and _that_ is what i presume contains the inode number of the running process (i_ino).
am i along the right lines, or should i be (according to proc_exe_link()) hunting down the struct vfsmount argument with mntget() instead? somehow i don't think so, but i haven't any point of reference to know in advance.
anyone with experience in the workings of proc and things, your input and advice greatly appreciated.
l.
Quoted 11 lines · Luke Kenneth Casson Leighton
is it possible to leverage - and i mean without cut/pasting large parts of kernel-space code into fireflier-in-userspace - the EXISTING kernel's iptables functionality in some way, such that per-program packet filtering may be performed?
ultimate aim:
to be able to "enhance" existing iptables firewall rule checking rather than to be backed into a corner of "replacing" existing functionality.... just because of one extra check [the pid]
Quoted 6 lines · Luke Kenneth Casson Leighton
so, my question, therefore, is:
what should i record in a modified version of
ipt_ownerin order to "vet" packets on a per-executable basis?should i consider recording the inode of the program's binary?
Bear in mind that that would make sense for an ACCEPT rule, but for a DROP rule, copying the binary would bypass the check.
Quoted 1 line
should i consider recording the _name_ of the program?
And bear in mind any user can set the name (I assume you mean the argv
[0] here) of their process to whatever they like, and then use the firewall rules for another program.
Maybe cryptographically checksumming all the executable file-backed maps would be closer to what you want. This ensures that the code you "trust" to do the right-thing(tm) on the network is the only code that can generate/receive whatever traffic. That approach has it's own issues though too.
Quoted 7 lines
for example, i notice in
ipt_owner.cthatmatch_pid()callsfind_task_by_pid(). okkkaaay... so... and then in fs/proc/base.c'sproc_exe_link(), i see thatget_task_mm()is called to get
something called anmm_struct. and theeeennn... dget is called
on _that_, and _then_ in struct dentry, there's something called ad_inode, and _that_ is what i presume contains the inode number of the running process (i_ino).
Firewalling on PID has rather obvious security ramifications, unless the PID is 0 or 1.
Quoted 4 lines
am i along the right lines, or should i be (according to
proc_exe_link()) hunting down the struct vfsmount argument withmntget()instead? somehow i don't think so, but i haven't any point of reference to know in advance.
Using paths to exec'ed binaries has problems too, as we have per-process namespaces etc..
I've seen no evidence that any existing firewall software has got this functionality right thus far.
HTH.
Signature · 3 lines
// Gianni Tedesco (gianni at scaramanga dot co dot uk) lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import 8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
Quoted 10 lines · Gianni Tedesco
Quoted 6 lines · Luke Kenneth Casson Leighton
so, my question, therefore, is:
what should i record in a modified version of
ipt_ownerin order to "vet" packets on a per-executable basis?should i consider recording the inode of the program's binary?
Bear in mind that that would make sense for an ACCEPT rule, but for a DROP rule, copying the binary would bypass the check.
i understand!
i thought that selinux by default would stop me from being able to copy binaries from /usr/bin.... uhn... no such luck.
if it becomes an issue i will investigate removing read access!
Quoted 5 lines
Quoted 1 line
should i consider recording the _name_ of the program?
And bear in mind any user can set the name (I assume you mean the argv
[0] here) of their process to whatever they like, and then use the firewall rules for another program.
so, inode it is.
Quoted 5 lines
Maybe cryptographically checksumming all the executable file-backed maps would be closer to what you want. This ensures that the code you "trust" to do the right-thing(tm) on the network is the only code that can generate/receive whatever traffic. That approach has it's own issues though too.
i should imagine that at some point down the line, selinux would be of some assistance here.
Quoted 11 lines
Quoted 7 lines
for example, i notice in
ipt_owner.cthatmatch_pid()callsfind_task_by_pid(). okkkaaay... so... and then in fs/proc/base.c'sproc_exe_link(), i see thatget_task_mm()is called to get
something called anmm_struct. and theeeennn... dget is called
on _that_, and _then_ in struct dentry, there's something called ad_inode, and _that_ is what i presume contains the inode number of the running process (i_ino).Firewalling on PID has rather obvious security ramifications, unless the PID is 0 or 1.
Quoted 7 lines
Quoted 4 lines
am i along the right lines, or should i be (according to
proc_exe_link()) hunting down the struct vfsmount argument withmntget()instead? somehow i don't think so, but i haven't any point of reference to know in advance.Using paths to exec'ed binaries has problems too, as we have per-process namespaces etc..
i'd be happy to set the rules by the "inode" of the program, and to have a userspace program do a lookup (at startup time) of the inode of the various programs, and load the rules for the appropriate set of binaries.
the only thing is of course installing new binaries, you need to reload the rules (new inodes).
i could kick that idiot responsible for dpkg maintenance.
russell's idea of providing /etc/dpkg/postinst.d is exactly the sort of thing that's required to re-run iptable-rule-reloading like this, and the idiot won't accept the patch.
l.
Quoted 12 lines · Luke Kenneth Casson Leighton
Quoted 10 lines · Gianni Tedesco
Quoted 6 lines · Luke Kenneth Casson Leighton
so, my question, therefore, is:
what should i record in a modified version of
ipt_ownerin order to "vet" packets on a per-executable basis?should i consider recording the inode of the program's binary?
Bear in mind that that would make sense for an ACCEPT rule, but for a DROP rule, copying the binary would bypass the check.
Quoted 6 lines
i understand!
i thought that selinux by default would stop me from being able to copy binaries from
/usr/bin.... uhn... no such luck.if it becomes an issue i will investigate removing read access!
okay.
first thing:
1) assuming that the DROP rule issue is one that cannot be avoided, and that a rules design policy of "deny everything and only allow specifics" is required, then checking on the _full_ pathname of the program is required.
second thing:
2) it _is_ possible to hunt through the selinux policy macros to remove the execute permission on binaries that a user drops into their home directory, or copies into their home directory.
l.
Signature · 7 lines
-- Truth, honesty and respect are rare commodities that all spring from the same well: Love. If you love yourself and everyone and everything around you, funnily and coincidentally enough, life gets a lot better. -- <a href="http://lkcl.net"> lkcl.net </a> <br /> <a href="mailto:[email protected]"> [email protected] </a> <br />