Discussion:
Netlink sockets and iptables NFLOG logging target
pragma
2014-04-24 18:23:08 UTC
Permalink
Hello SEAndroid folks,

I created and maintain an Android app called Network Log. It uses iptables
logging to monitor network transmissions and record statistics about them.

Historically, Android has shipped with a Linux kernel with the
iptables/netfilter LOG (CONFIG_NETFILTER_XT_TARGET_LOG) target enabled. To
monitor the logging using the LOG target, you would typically read
/proc/kmsg and watch for the logging output. Network Log has no problems
doing this with SEAndroid since it uses the system's grep or cat commands
in a su root shell to read /proc/kmsg.

However, more recent Android systems have been using the newer(ish) NFLOG
(CONFIG_NETFILTER_XT_TARGET_NFLOG) target instead. This target requires
using netlink sockets to read the logging information. My app uses a
native binary based on http://netfilter.org/projects/libnetfilter_log/ to
interact with NFLOG. The app installs this binary to the app's files
location (/data/data/com.googlecode.networklog/files/) and executes it in a
su root shell. This has been working successfully until SEAndroid started
shipping in Enforcing mode.

My question is: Is there a simple way for the app or the end-user to allow
the nflog binary to run without being restricted? What would be your
recommendations? Alternatively, might there be a better approach for
interacting with NFLOG of which SEAndroid is more tolerant?

Thanks for your attention.
Stephen Smalley
2014-04-24 19:32:59 UTC
Permalink
Post by pragma
Hello SEAndroid folks,
I created and maintain an Android app called Network Log. It uses
iptables logging to monitor network transmissions and record statistics
about them.
Historically, Android has shipped with a Linux kernel with the
iptables/netfilter LOG (CONFIG_NETFILTER_XT_TARGET_LOG) target enabled.
To monitor the logging using the LOG target, you would typically read
/proc/kmsg and watch for the logging output. Network Log has no
problems doing this with SEAndroid since it uses the system's grep or
cat commands in a su root shell to read /proc/kmsg.
However, more recent Android systems have been using the newer(ish)
NFLOG (CONFIG_NETFILTER_XT_TARGET_NFLOG) target instead. This target
requires using netlink sockets to read the logging information. My app
uses a native binary based on
http://netfilter.org/projects/libnetfilter_log/ to interact with NFLOG.
The app installs this binary to the app's files location
(/data/data/com.googlecode.networklog/files/) and executes it in a su
root shell. This has been working successfully until SEAndroid started
shipping in Enforcing mode.
My question is: Is there a simple way for the app or the end-user to
allow the nflog binary to run without being restricted? What would be
your recommendations? Alternatively, might there be a better approach
for interacting with NFLOG of which SEAndroid is more tolerant?
Thanks for your attention.
You need to move away from having your app directly execute setuid
helpers (which is already disabled in Android 4.3 and later even apart
from SELinux by nosuid mount of /system) and instead have it get its
information from a legitimate service running on the platform that has
the necessary access rights. So if you want this information to be
available to apps, it needs to be read by some system service and then
exported to apps via an API, not directly collected by the app.
pragma
2014-04-24 21:20:32 UTC
Permalink
Thanks for the response.

They aren't setuid binaries. The app invokes an interactive root shell
by executing su and then piping shell commands to it and reading
from it.

There does not appear to be any system service for interacting with
NFLOG, which is why the nflog binary was created.

I read your paper, "Security Enhanced (SE) Android: Bringing
Flexible MAC to Android", and there is this statement in it:

"Next, the policy denied GingerBreak’s attempt to create
the netlink socket, as there is no legitimate need for user
shells or apps to create this type of socket."

I do think that using netlink sockets to be able to read NFLOG
entries is a legitimate need, especially since there is no such
system service for this and that there is unlikely to be one.

But in any case, I'm not very familiar with SELinux/SEAndroid
commands, and I would like to know if there's a simple way
for the app or the end-user to allow the nflog binary to access
netlink sockets.

I am hoping for something not so all-or-nothing as executing
'setenforce 0' and less invasive then moving the binary to
/system and chowning/chmodding it to be a system command.
Ideally, it'd be great if it were possible for the user to set an
exemption or to change the context -- is this or something similar
possible?
Post by Stephen Smalley
Post by pragma
Hello SEAndroid folks,
I created and maintain an Android app called Network Log. It uses
iptables logging to monitor network transmissions and record statistics
about them.
Historically, Android has shipped with a Linux kernel with the
iptables/netfilter LOG (CONFIG_NETFILTER_XT_TARGET_LOG) target enabled.
To monitor the logging using the LOG target, you would typically read
/proc/kmsg and watch for the logging output. Network Log has no
problems doing this with SEAndroid since it uses the system's grep or
cat commands in a su root shell to read /proc/kmsg.
However, more recent Android systems have been using the newer(ish)
NFLOG (CONFIG_NETFILTER_XT_TARGET_NFLOG) target instead. This target
requires using netlink sockets to read the logging information. My app
uses a native binary based on
http://netfilter.org/projects/libnetfilter_log/ to interact with NFLOG.
The app installs this binary to the app's files location
(/data/data/com.googlecode.networklog/files/) and executes it in a su
root shell. This has been working successfully until SEAndroid started
shipping in Enforcing mode.
My question is: Is there a simple way for the app or the end-user to
allow the nflog binary to run without being restricted? What would be
your recommendations? Alternatively, might there be a better approach
for interacting with NFLOG of which SEAndroid is more tolerant?
Thanks for your attention.
You need to move away from having your app directly execute setuid
helpers (which is already disabled in Android 4.3 and later even apart
from SELinux by nosuid mount of /system) and instead have it get its
information from a legitimate service running on the platform that has
the necessary access rights. So if you want this information to be
available to apps, it needs to be read by some system service and then
exported to apps via an API, not directly collected by the app.
Stephen Smalley
2014-04-25 13:00:48 UTC
Permalink
Post by pragma
Thanks for the response.
They aren't setuid binaries. The app invokes an interactive root shell
by executing su and then piping shell commands to it and reading
from it.
I assume you are referring to the form of su that runs as a daemon
(launched via a custom install-recovery.sh) and receives commands over a
socket? In that case, the su daemon runs in init's domain since there
is no domain transition defined for install-recovery.sh, and any shell
it spawns runs in the init_shell domain. Both of those domains are
unconfined domains and therefore are completely unrestricted in current
Android releases, although certain restrictions have been imposed even
on unconfined domains in AOSP master.
Post by pragma
I read your paper, "Security Enhanced (SE) Android: Bringing
"Next, the policy denied GingerBreak’s attempt to create
the netlink socket, as there is no legitimate need for user
shells or apps to create this type of socket."
I do think that using netlink sockets to be able to read NFLOG
entries is a legitimate need, especially since there is no such
system service for this and that there is unlikely to be one.
If it requires root, then it isn't really supported for apps by Android
regardless of SELinux; you already need a custom ROM / rooted device in
order to use such commands from an app in that situation. Whereas if
you can get a system service to provide such functionality, then you can
enable your app to work on stock Android. In the Gingerbreak example,
the specific netlink protocol was allowed for non-root processes by
Linux, so only SELinux restricted it. Note that SELinux can distinguish
among different netlink protocols (at least to the extent to which we
have defined separate classes in the kernel and policy), so it can for
example distinguish NETLINK_NFLOG from NETLINK_KOBJECT_UEVENT sockets.
Post by pragma
But in any case, I'm not very familiar with SELinux/SEAndroid
commands, and I would like to know if there's a simple way
for the app or the end-user to allow the nflog binary to access
netlink sockets.
I am hoping for something not so all-or-nothing as executing
'setenforce 0' and less invasive then moving the binary to
/system and chowning/chmodding it to be a system command.
Ideally, it'd be great if it were possible for the user to set an
exemption or to change the context -- is this or something similar
possible?
If you are relying on the su daemon approach, then I wouldn't expect it
to fail under current policies, as the init and init_shell domains are
unconfined domains and would in fact be allowed to create and use
NETLINK_NFLOG sockets. If it is failing for you on current Android, can
you show the actual avc: denied messages from dmesg?

That said, I can see that this will likely break under the AOSP master
policy because there we have taken away the ability of unconfined
domains to execute files from /data. That's a security enhancement to
prevent running unauthorized code with privilege. For that, you will
need to copy your binary to /system or change the policy. On a rooted
device, you certainly have the power to change the policy, but that
requires you to clone the AOSP tree, modify the policy sources, and
rebuild a new policy. Or you could use a tool like sepolicy-inject [1]
to modify the existing binary policy file and then reload that.

[1] https://bitbucket.org/joshua_brindle/sepolicy-inject
pragma
2014-04-25 16:05:50 UTC
Permalink
Thanks again for the excellent response.

I received a report of the failure from a user out in the field, and I
have actually not yet reproduced it personally since I've refrained
from upgrading Android on my device because I am a heavy user
of root apps and am leery of SEAndroid breaking my tools. But
I suppose it's time to bite that bullet and learn how to work with
SEAndroid policies.

I am somewhat concerned about the ramifications of using
sepolicy-inject on an end-user's device. I could display a dialog
explaining that I intend to update their SEAndroid policy to allow
executing a binary from the /data folder and only continue if they
explicitly confirm the action. I will have to learn how to do this
so that only the nflog binary belonging to the app is allowed
rather than allowing all binaries in /data to be executed. As
I said, it's time for me to get with the times and learn about
SEAndroid!
Post by Stephen Smalley
Post by pragma
Thanks for the response.
They aren't setuid binaries. The app invokes an interactive root shell
by executing su and then piping shell commands to it and reading
from it.
I assume you are referring to the form of su that runs as a daemon
(launched via a custom install-recovery.sh) and receives commands over a
socket? In that case, the su daemon runs in init's domain since there
is no domain transition defined for install-recovery.sh, and any shell
it spawns runs in the init_shell domain. Both of those domains are
unconfined domains and therefore are completely unrestricted in current
Android releases, although certain restrictions have been imposed even
on unconfined domains in AOSP master.
Post by pragma
I read your paper, "Security Enhanced (SE) Android: Bringing
"Next, the policy denied GingerBreak’s attempt to create
the netlink socket, as there is no legitimate need for user
shells or apps to create this type of socket."
I do think that using netlink sockets to be able to read NFLOG
entries is a legitimate need, especially since there is no such
system service for this and that there is unlikely to be one.
If it requires root, then it isn't really supported for apps by Android
regardless of SELinux; you already need a custom ROM / rooted device in
order to use such commands from an app in that situation. Whereas if
you can get a system service to provide such functionality, then you can
enable your app to work on stock Android. In the Gingerbreak example,
the specific netlink protocol was allowed for non-root processes by
Linux, so only SELinux restricted it. Note that SELinux can distinguish
among different netlink protocols (at least to the extent to which we
have defined separate classes in the kernel and policy), so it can for
example distinguish NETLINK_NFLOG from NETLINK_KOBJECT_UEVENT sockets.
Post by pragma
But in any case, I'm not very familiar with SELinux/SEAndroid
commands, and I would like to know if there's a simple way
for the app or the end-user to allow the nflog binary to access
netlink sockets.
I am hoping for something not so all-or-nothing as executing
'setenforce 0' and less invasive then moving the binary to
/system and chowning/chmodding it to be a system command.
Ideally, it'd be great if it were possible for the user to set an
exemption or to change the context -- is this or something similar
possible?
If you are relying on the su daemon approach, then I wouldn't expect it
to fail under current policies, as the init and init_shell domains are
unconfined domains and would in fact be allowed to create and use
NETLINK_NFLOG sockets. If it is failing for you on current Android, can
you show the actual avc: denied messages from dmesg?
That said, I can see that this will likely break under the AOSP master
policy because there we have taken away the ability of unconfined
domains to execute files from /data. That's a security enhancement to
prevent running unauthorized code with privilege. For that, you will
need to copy your binary to /system or change the policy. On a rooted
device, you certainly have the power to change the policy, but that
requires you to clone the AOSP tree, modify the policy sources, and
rebuild a new policy. Or you could use a tool like sepolicy-inject [1]
to modify the existing binary policy file and then reload that.
[1] https://bitbucket.org/joshua_brindle/sepolicy-inject
pragma
2014-04-25 16:21:19 UTC
Permalink
Oh, and yes, your assumptions are indeed correct. It
is a su binary launched as a daemon.

And I'm glad to hear that SEAndroid can distinguish
different types of netlink sockets. So, I could allow
NETLINK_NFLOG sockets with sepolicy-inject, if it
does becomes necessary to do so.
Post by pragma
Thanks again for the excellent response.
I received a report of the failure from a user out in the field, and I
have actually not yet reproduced it personally since I've refrained
from upgrading Android on my device because I am a heavy user
of root apps and am leery of SEAndroid breaking my tools. But
I suppose it's time to bite that bullet and learn how to work with
SEAndroid policies.
I am somewhat concerned about the ramifications of using
sepolicy-inject on an end-user's device. I could display a dialog
explaining that I intend to update their SEAndroid policy to allow
executing a binary from the /data folder and only continue if they
explicitly confirm the action. I will have to learn how to do this
so that only the nflog binary belonging to the app is allowed
rather than allowing all binaries in /data to be executed. As
I said, it's time for me to get with the times and learn about
SEAndroid!
Post by Stephen Smalley
Post by pragma
Thanks for the response.
They aren't setuid binaries. The app invokes an interactive root shell
by executing su and then piping shell commands to it and reading
from it.
I assume you are referring to the form of su that runs as a daemon
(launched via a custom install-recovery.sh) and receives commands over a
socket? In that case, the su daemon runs in init's domain since there
is no domain transition defined for install-recovery.sh, and any shell
it spawns runs in the init_shell domain. Both of those domains are
unconfined domains and therefore are completely unrestricted in current
Android releases, although certain restrictions have been imposed even
on unconfined domains in AOSP master.
Post by pragma
I read your paper, "Security Enhanced (SE) Android: Bringing
"Next, the policy denied GingerBreak’s attempt to create
the netlink socket, as there is no legitimate need for user
shells or apps to create this type of socket."
I do think that using netlink sockets to be able to read NFLOG
entries is a legitimate need, especially since there is no such
system service for this and that there is unlikely to be one.
If it requires root, then it isn't really supported for apps by Android
regardless of SELinux; you already need a custom ROM / rooted device in
order to use such commands from an app in that situation. Whereas if
you can get a system service to provide such functionality, then you can
enable your app to work on stock Android. In the Gingerbreak example,
the specific netlink protocol was allowed for non-root processes by
Linux, so only SELinux restricted it. Note that SELinux can distinguish
among different netlink protocols (at least to the extent to which we
have defined separate classes in the kernel and policy), so it can for
example distinguish NETLINK_NFLOG from NETLINK_KOBJECT_UEVENT sockets.
Post by pragma
But in any case, I'm not very familiar with SELinux/SEAndroid
commands, and I would like to know if there's a simple way
for the app or the end-user to allow the nflog binary to access
netlink sockets.
I am hoping for something not so all-or-nothing as executing
'setenforce 0' and less invasive then moving the binary to
/system and chowning/chmodding it to be a system command.
Ideally, it'd be great if it were possible for the user to set an
exemption or to change the context -- is this or something similar
possible?
If you are relying on the su daemon approach, then I wouldn't expect it
to fail under current policies, as the init and init_shell domains are
unconfined domains and would in fact be allowed to create and use
NETLINK_NFLOG sockets. If it is failing for you on current Android, can
you show the actual avc: denied messages from dmesg?
That said, I can see that this will likely break under the AOSP master
policy because there we have taken away the ability of unconfined
domains to execute files from /data. That's a security enhancement to
prevent running unauthorized code with privilege. For that, you will
need to copy your binary to /system or change the policy. On a rooted
device, you certainly have the power to change the policy, but that
requires you to clone the AOSP tree, modify the policy sources, and
rebuild a new policy. Or you could use a tool like sepolicy-inject [1]
to modify the existing binary policy file and then reload that.
[1] https://bitbucket.org/joshua_brindle/sepolicy-inject
Stephen Smalley
2014-04-25 17:59:59 UTC
Permalink
Post by pragma
Thanks again for the excellent response.
I received a report of the failure from a user out in the field, and I
have actually not yet reproduced it personally since I've refrained
from upgrading Android on my device because I am a heavy user
of root apps and am leery of SEAndroid breaking my tools. But
I suppose it's time to bite that bullet and learn how to work with
SEAndroid policies.
I am somewhat concerned about the ramifications of using
sepolicy-inject on an end-user's device. I could display a dialog
explaining that I intend to update their SEAndroid policy to allow
executing a binary from the /data folder and only continue if they
explicitly confirm the action. I will have to learn how to do this
so that only the nflog binary belonging to the app is allowed
rather than allowing all binaries in /data to be executed. As
I said, it's time for me to get with the times and learn about
SEAndroid!
So, a couple of observations and a pointer:

- I think you'll find it much easier to just install your helper to
/system rather than trying to modify the policy on the device. If
however you truly want to chase down this path...

- sepolicy-inject will just let you generate a modified kernel policy
file with your additional rule. You still need some way of loading it
into the kernel. The officially supported way is to write it to one of
the supported policy file locations and then do a setprop
selinux.reload_policy 1 to trigger a reload by init. In current Android
releases, the officially supported location for policy updates is
/data/security/current/sepolicy (the original policy is loaded from
/sepolicy, but you obviously cannot persistently change that without
regenerating the boot image and reflashing it). On Samsung devices
though I think they are still using /data/security/sepolicy (the
original, pre-4.3 location), not /data/security/current/sepolicy (Google
moved the files to a subdirectory in AOSP 4.3 release for use by their
SELinuxPolicyInstallReceiver). Whether or not that mechanism will still
work in the future is unclear; it was recently reverted in AOSP master
due to some problems with respect to incompatibility between policy
updates installed this way and OTAs. We have a set of patches uploaded
to AOSP to try to introduce a version checking mechanism to resolve this.

- To truly limit what can be executed from /data would require your app
to be labeled differently than other apps, which would require modifying
not only sepolicy but also mac_permissions.xml and seapp_contexts so
that its /data/data files are labeled with a distinct type that can then
be made executable by the su daemon process.

I'll be giving a talk at the Android Builders Summit next week that may
be helpful; the slides are already available from:
http://events.linuxfoundation.org/events/android-builders-summit/program/slides
Loading...