|Priority:||4 - Normal|
|Created by:||Former user|
|Reported by:||Former user|
This ticket encompasses the work to emit AUDIT_PATH (1302) records out to the auditd. This includes adding these events to any syscalls which require them, even if there is no file system watch. For example, an audit event for the
open syscall should also emit an AUDIT_PATH record for the file being opened. A PATH record looks like this:
type=PATH msg=audit(1525901041.051:3730): item=0 name="/etc/audit/audit.rules" inode=287783 dev=fd:01 mode=0100640 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
Here is the TL;DR summary for this work
1) If syscall fails, emit CWD record and nothing else (for now) 2) Special case for chdir syscall, record cwd in lwp on entry, then free on return, otherwise just getcwd when emitting records 3) Use flags on syscall to copyin the path arg(s) and format/emit PATH record 4) For the "nametype", most of this can be inferred from the syscall. a) open and openat need special handling b) for now, if create flag is set, just call it a CREATE
The initial work for OS-6212 only emits a single
SYSCALL audit record for the syscall itself, however Linux emits a set of multiple records when a syscall audit event occurs.
This ticket is focused on emitting the
PATH records for a syscall audit event. There are other records which Linux will emit, but those can be handled by other tickets.
Note that all of the audit records emitted in a set must have the same timestamp and serial number. This is how records can be grouped into a single event.
All syscall events need to emit a
CWD record. This is fairly simple since we can get the CWD when we're emitted the audit records. A
CWD record looks like this
type=CWD msg=audit(1526471369.163:42901): cwd="/home/jerry"
Note that there is one complexity with CWD, which is that represents the directory when the syscall starts. Thus, for a
chdir sycall we need to record original CWD at the start of the syscall. For efficiency, we can only do this when auditing is in use and only for the
chdir syscall. We can save the CWD in the lx brand LWP data and free it at the end of the syscall. All other syscalls could simply get the CWD when the set of audit records are being emitted.
The following list of syscalls will emit one or more
PATH audit records. My design for handling this is that we use some bits from the
sy_flags member of the
lx_sysent_t structure to indicate which audit records to emit, then update the
lx_sysent32 syscall tables to flag the relevant syscalls. We need 3 bits to indicate which arguments to the syscall need audit records:
0x010 LX_AUDIT_PATH0 0x020 LX_AUDIT_PATH1 0x030 LX_AUDIT_PATH01 0x040 LX_AUDIT_PATH02 0x050 LX_AUDIT_PATH13
For example, the open syscall needs a
PATH record emitted for argument 0, so we will tag that syscall with
symlink syscall needs 2
PATH records emitted, one for argument 0 and one for argument 2, so we will tag that syscall with
LX_AUDIT_PATH02. Similarly, the
renameat syscall needs 2
PATH records, one for argument 1 and one for argument 3, so it is tagged with
Here is the full list of syscalls which need
open LX_AUDIT_PATH0 stat LX_AUDIT_PATH0 lstat LX_AUDIT_PATH0 access LX_AUDIT_PATH0 execve LX_AUDIT_PATH0 (item 0 is exec pathname) truncate LX_AUDIT_PATH0 chdir LX_AUDIT_PATH0 (cwd is original dir, item 0 new dir) rename LX_AUDIT_PATH01 mkdir LX_AUDIT_PATH0 rmdir LX_AUDIT_PATH0 creat LX_AUDIT_PATH0 link LX_AUDIT_PATH01 unlink LX_AUDIT_PATH0 symlink LX_AUDIT_PATH01 (item 0 is target, item 2 is symlink name) readlink LX_AUDIT_PATH0 chmod LX_AUDIT_PATH0 chown LX_AUDIT_PATH0 lchown LX_AUDIT_PATH0 chroot LX_AUDIT_PATH0 mknod LX_AUDIT_PATH0 statfs LX_AUDIT_PATH0 mount LX_AUDIT_PATH1 (path record is target mount point) umount LX_AUDIT_PATH0 (32-bit only) umount2 LX_AUDIT_PATH0 (path record is mount point) setxattr LX_AUDIT_PATH0 lsetxattr LX_AUDIT_PATH0 getxattr LX_AUDIT_PATH0 lgetxattr LX_AUDIT_PATH0 listxattr LX_AUDIT_PATH0 llistxattr LX_AUDIT_PATH0 removexattr LX_AUDIT_PATH0 lremovexattr LX_AUDIT_PATH0 openat LX_AUDIT_PATH1 mkdirat LX_AUDIT_PATH1 mknodat LX_AUDIT_PATH1 fchownat LX_AUDIT_PATH1 fstatat LX_AUDIT_PATH1 unlinkat LX_AUDIT_PATH1 renameat LX_AUDIT_PATH13 linkat LX_AUDIT_PATH13 symlinkat LX_AUDIT_PATH02 readlinkat LX_AUDIT_PATH1 fchmodat LX_AUDIT_PATH1 faccessat LX_AUDIT_PATH1
When we're emitting a
SYSCALL record, we can check the syscall table and if it is tagged with any of these flags, we can emit the appropriate additional audit records.
The way that Linux emits the
PATH records should be easy to handle. The record is simply the string as passed in to the syscall, so there is no work needed to resolve the string to the real path. For example, if the path string is "foo", then "foo" is used in the record, if it is "../mydir/foo", then that string is used, as so on. For each filetype
PATH record, there is also an associated
PARENT record. This is equivalent to the
dirname on the path. So, for the path string "./foo", the
PARENT record would be "./", or for the path string "../mydir/foo", the
PARENT record is "../mydir/". When only a bare path string is used, then the
PARENT record is the CWD, so a path string of "foo" would get an associated
PARENT record populated with the CWD.
Here is an example of the two
PATH records emitted from an
open syscall audit event:
type=PATH msg=audit(1526475236.547:43359): item=0 name="/var/log/audit/" inode=369669 dev=fd:01 mode=040750 ouid=0 ogid=0 rdev=00:00 nametype=PARENT type=PATH msg=audit(1526475236.547:43359): item=1 name="/var/log/audit/.audit.log.swp" inode=287786 dev=fd:01 mode=0100600 ouid=0 ogid=0 rdev=00:00 nametype=CREATE
Note that the first record is tagged as the
PARENT and the second record is the actual file. Also note that the
item field increments, so if we had 4 audit records (e.g. from
rename) then there would be 4 path records with item values 0-3.
When we have to emit
PATH records, we can
copyin the relevant syscall parameters and format the records using that string data. The first 4 syscall arguments are already being saved in
br_syscall_args in the brand LWP struct as part of the work for OS-6212.
nametype on the audit records is either
PARENT or one of;
NORMAL record is just emitted when accessing an existing file.
DELETE is emitted when the file is being created or removed. In general, the
nametype is obvious from the syscall. For example, if the audit record is for the
rename syscall, the old path will have a
DELETE record and the new path will have a
There is one complexity with the
openat syscalls since the
nametype could be either
CREATE. It is not easy for us to handle this at audit record time since the actual determination of create vs. normal is embedded down in the various file systems. To avoid having to stat the path ahead of performing the open syscall (which may not even need an audit record), it seems reasonable to simply emit a
CREATE record if the
O_CREAT flag is set on the syscall, otherwise emit a
NORMAL record. We could revisit this later if it becomes important.
When the syscall fails, Linux can emit some
PATH records, but it varies on which records are emitted, and there is not always enough records to actually reconstruct what the syscall arguments were. For now, it seems reasonable for us to simply not emit
PATH records if the syscall fails. Again, we could revisit this later if it becomes important.
While cleaning up workspaces, I found that I had started work on this about a year ago. I don't know if the work that I started will be useful should I or someone else pick it up or not. Attaching just in case: OS-6951.patch