REASON 1:
Apart from traditional Discretionary Access Control (DAC), - that makes use of *NIX owner/group/mode of processes/files to allow/deny access - Android implements several other access control mechanisms of Linux kernel to make itself more secure, such as Seccomp Filter was implemented in Oreo.
REASON 2:
While DAC is allowed by-default
, SELinux (a Mandatory Access Control) works in denied by-default
mode. Any access attempt that isn't explicitly allowed in an SE Policy rule will be denied. Using same, access to /proc
fs has been tightened in Android O which won't let a non-privileged process/user read - e.g. - /proc/stat and /proc/filesystem
. Same restricts you from reading /proc/1
when running as a non-root user from your app.
If SELinux on your device isn't Enforcing
, you should be able to read /proc/1
but there are some other security restrictions which - unlike DAC and MAC - are specific to /proc
pseudo filesystem.
REASON 3:
Android by-default mounts /proc
with hidepid=2,gid=3009 options, which means a non-privileged user will be able to view only its own processes (running with same UID) (ref). So your app won't be able to see directory /proc/1
. The only exception is the processes which are member of group AID_READPROC (GID 3009).
REASON 4:
But still if you (re-)mount /proc
without option hidepid
, you won't be able to read /proc/1/maps
because Linux kernel only permits processes having capability SYS_PTRACE to read the details of currently mapped memory regions.
An example of working non-root process on Android is incidentd that runs with CAP_SYS_PTRACE
as well as a member of group READPROC
. Also the SE Policy rule like following should be defined to allow access:
allow incidentd init : file {
read getattr open
}
LOGGING:
As far as logging of permission denials is concerned, logd
(the service from which logcat
reads) is an Android specific logging daemon which necessarily logs events from within Android's native and Java framework (such as manifest permission denials), but optionally includes kernel events (which we can also see using native command line tool dmesg
). SELinux denials are also logged to kernel log:
$ ls /proc/1
ls: cannot access '/proc/1': Permission denied
# dmesg | grep avc
[37914.650314] type=1400 audit(1548757064.171:33323): avc: denied {
getattr
}
for pid=28576 comm="ls" path="/proc/1" dev="proc" ino=803674 scontext=u:r:untrusted_app_27:s0:c512,c768 tcontext=u:r:init:s0 tclass=dir permissive=0
# logcat | grep avc
01-29 14:17:44.171 28576 28576 W ls
: type=1400 audit(0.0:33323): avc: denied {
getattr
}
for path="/proc/1" dev="proc" ino=803674 scontext=u:r:untrusted_app_27:s0:c512,c768 tcontext=u:r:init:s0 tclass=dir permissive=0
However Linux kernel may or may not log all of its internal permission denials depending on multiple build and runtime configurations including printk loglevel
, DYNAMIC_DEBUG
and/or others I'm not sure of. Therefore such messages may not appear in logs.
If you want to get logs related to security events, you can make use of Linux kernel's Auditing System
. For that you need to use auditctl
tool for defining rules (root required), and you would get details about the denials in logs through dmesg
or logcat
. Fo more details on how to define rules, see this answer.
PS:
Another reason of not being able to access a certain PID in procfs is PID namespace
that isn't relevant on Android so far but very common for isolation mechanisms like containers. In a new PID namespace, any process from parent namespace isn't visible and a process could have same PID (including PID 1; init) as that of some other process in some other PID namespace.