audit.78 kernel
by David Woodhouse
* Fri Jul 15 2005 David Woodhouse <dwmw2(a)redhat.com> audit.78
- Fix livelock in audit_serial()
--
dwmw2
19 years, 5 months
audit 0.9.19 released
by Steve Grubb
Hi,
I've just released a new version of the audit daemon. It can be downloaded
from http://people.redhat.com/sgrubb/audit It will also be in rawhide
tomorrow. The Changelog is:
- removed debug code from ausearch
It turns out there was a lone "if" statement accidentally left in from
debugging earlier this week. This was causing segfaults when ausearch -m USER
was issued.
Please let me know if there are any other problems.
-Steve
19 years, 5 months
splinter work on generic fs notification framework
by Timothy R. Chavez
Hi,
I've CCed some folks that I thought might be interested in this update and may
not be on linux-audit.
Based on recent discussion on LKML and some IRC conversations, a generic file
system notification framework is being written to merge common functionality
between the "auditfs" component of the audit framework and Inotify. This
framework will be mostly comprised of the watch logic implemented by the
"auditfs" component (I_AUDIT, hash table, update hook, helper functions, etc)
and the fsnotify hooks written by Robert Love. User's of this framework will
pass their own callback functions in when adding a watch via this framework
which will effectively be stored on the watch and called from the watch hook
that discovers it.
We introduce fs/watch.c and include/linux/watch.h
Some of the oustanding issues:
o The fsnotify hooks will need to be expanded to cover more of the file system
to fufill CAPP's needs.
o The way we did "movement" notifications is different how Inotify did them.
The trick is to do it such that its mutually beneficial.
o The interface for adding and removing watches should be the same for every
user. I think that the audit_receive_watch|audit_insert/remove_watch bit was
quite slopply done *pats self on back*, so I think this gives me a chance to
redeem myself and make something functional and slightly more sexy.
o Filtering. Should the MAY_* stuff be scrapped... How important is it? I
think it's a bit sloppy and contrived too. It's a fine concept. We'd
ideally like to mitigate throughput where possible, but I think the
'ausearch' tool should work fine for looking only and what's "interesting"
and the netlink speed-up coupled with the backlogs work should help buffer
any impact introduced by the extra records. Opinions?
o I'd like to place an extra field in the record that tells you exactly what
type of action it was... trying to deduce from system call is a bit...
cumbersome... might be nice to have in the log, "action=MODIFIED" or
something.
Feel free to add something..
I'm sure I'm forgetting some things, but I really should get back to work :)
Anyway... it's a start
-tim
19 years, 5 months
audit 0.9.18 released
by Steve Grubb
Hi,
I've just released a new version of the audit daemon. It can be downloaded
from http://people.redhat.com/sgrubb/audit It will also be in rawhide
tomorrow. The Changelog is:
- auditd message formatter use MAX_AUDIT_MESSAGE_LENGTH to prevent clipping
This is a bug fix release. Please let me know if there are any other problems.
-Steve
19 years, 5 months
audit.77 kernel
by David Woodhouse
* Wed Jul 13 2005 David Woodhouse <dwmw2(a)redhat.com> audit.77
- Use GFP_ATOMIC from audit_free() to avoid scheduling in idle thread
--
dwmw2
19 years, 5 months
audit.76 kernel
by David Woodhouse
* Wed Jul 13 2005 David Woodhouse <dwmw2(a)redhat.com> audit.76
- Avoid auditing the whole auditd process, not just the one thread
* Wed Jul 13 2005 David Woodhouse <dwmw2(a)redhat.com> audit.75
- Fix rmmod race condition with O_NONBLOCK
- Correct auditfs hooks
--
dwmw2
19 years, 5 months
Re: audit 0.9.17 released
by Linda Knippers
> Does anyone know of any other bugs regarding audit daemon & utilities?
I don't know that what I'm seeing is a problem with the tools or with
the kernel but I can get my system into a state where I'm seeing lots
of audit records for auditd. The records are for a pid one greater
than the pid that 'auditctl -s' reports.
I'm running the .74 kernel and the 0.9.16 tools on a 2-cpu em64t system
running the x84_64 kernel. I've seen the same condition on my 2-cpu
ia64 box. The condition is semi-repeatable and happens when I've
got a heavy audit load going.
I first saw the condition when running the testfileperms test, trying
to reproduce the panic that Tim/Michael reported. I start it up as
root in a loop in one window:
# while true ; do testfileperms /proc ljk ljk ; done
While this is running, I go through a sequence of restarting the
auditd and enabling syscall auditing for uid=0. (See attached
script.) When the condition happens (it doesn't always), the
system will appear to freeze for about a minute and then start
going again. At this point the audit logs will show huge numbers
of audit records for auditd, then a few for the test program, then
a huge number for auditd, etc. My script shuts off auditing right
away as this test will cycle through the logs very quickly.
What I see is stuff like this. If 'auditctl -s' shows this:
# /sbin/auditctl -s
AUDIT_STATUS: enabled=1 flag=1 pid=3332 rate_limit=0 backlog_limit=256 lost=17986 backlog=0
I'll get audit records like this:
type=SYSCALL msg=audit(1121284091.842:3559675): arch=c000003e syscall=1 success=yes exit=246 a0=4
a1=2a9556c000 a2=f6 a3=53 items=0 pid=3333 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0
sgid=0 fsgid=0 comm="auditd" exe="/sbin/auditd"
type=SYSCALL msg=audit(1121284091.842:3559676): arch=c000003e syscall=5 success=yes exit=0 a0=4
a1=409fffd0 a2=409fffd0 a3=1 items=0 pid=3333 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
egid=0 sgid=0 fsgid=0 comm="auditd" exe="/sbin/auditd"
type=SYSCALL msg=audit(1121284091.842:3559677): arch=c000003e syscall=138 success=yes exit=0 a0=4
a1=40a00000 a2=409fffd0 a3=1 items=0 pid=3333 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
egid=0 sgid=0 fsgid=0 comm="auditd" exe="/sbin/auditd"
type=SYSCALL msg=audit(1121284091.842:3559678): arch=c000003e syscall=202 success=yes exit=1
a0=552abc7b28 a1=1 a2=1 a3=1 items=0 pid=3333 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
egid=0 sgid=0 fsgid=0 comm="auditd" exe="/sbin/auditd"
Notice the pid. Is this the worker thread? I don't have sysrq-T data
from this example but from a previous examples, its shown auditd info like
this:
Jul 13 15:18:53 cert-e2 kernel: auditd S 0000000100426fe9 0 3174 1 3175
2218 (NOTLB)
Jul 13 15:18:53 cert-e2 kernel: 000001007041bd48 0000000000000006 0000211c00000040 000000d000000004
Jul 13 15:18:53 cert-e2 kernel: 000001007e5ed690 0000000000003139 ffffffff80411b00
000001007e5ed978
Jul 13 15:18:53 cert-e2 kernel: 00000000000000d0 0000000000000246
Jul 13 15:18:53 cert-e2 kernel: Call Trace:<ffffffff8034ad3e>{schedule_timeout+287}
<ffffffff80142e28>{process_timeout+0}
Jul 13 15:18:53 cert-e2 kernel: <ffffffff802e496b>{datagram_poll+42}
<ffffffff801a17c6>{do_select+1435}
Jul 13 15:18:53 cert-e2 kernel: <ffffffff801a1171>{__pollwait+0}
<ffffffff801a1b45>{sys_select+820}
Jul 13 15:18:53 cert-e2 kernel: <ffffffff80110a2a>{tracesys+209}
Jul 13 15:18:53 cert-e2 kernel: auditd S 000001007041ddf8 0 3175 1
3174 (NOTLB)
Jul 13 15:18:53 cert-e2 kernel: 000001007041dd48 0000000000000006 0000000042d568a5 000000732931e820
Jul 13 15:18:53 cert-e2 kernel: 000001006ecef2d0 000000000001a5eb 00000100727f5710
000001006ecef5b8
Jul 13 15:18:53 cert-e2 kernel: 0000000000000004 0000000000000000
Jul 13 15:18:53 cert-e2 kernel: Call Trace:<ffffffff8034ac84>{schedule_timeout+101}
<ffffffff8017a389>{find_extend_vma+22}
Jul 13 15:18:53 cert-e2 kernel: <ffffffff80154dfa>{queue_me+95} <ffffffff80155283>{do_futex+422}
Jul 13 15:18:53 cert-e2 kernel: <ffffffff8013377e>{default_wake_function+0}
<ffffffff8013377e>{default_wake_function+0}
Jul 13 15:18:53 cert-e2 kernel: <ffffffff80188695>{sys_fstatfs+98}
<ffffffff8015573d>{sys_futex+204}
Jul 13 15:18:53 cert-e2 kernel: <ffffffff80110a2a>{tracesys+209}
I can get this to happen on perhaps half my attempts on the x86_64 system.
Let me know if more info would be helpful.
-- ljk
set -x
# Make sure the test program is running:
## while true ; do testfileperms /proc ljk ljk ; done
# Stop/start audit
/etc/init.d/auditd stop
/etc/init.d/auditd start
# look at stuff
ps axlw |grep audit
/sbin/auditctl -s
echo "1" > /proc/sys/kernel/sysrq
echo t > /proc/sysrq-trigger
# enable syscall auditing for uid=0
/sbin/auditctl -a entry,always -S all -F uid=0
# if things got slow, then its happened
sleep 1
echo t > /proc/sysrq-trigger
#stop things
/sbin/auditctl -e 0
/**********************************************************************
** Copyright (C) International Business Machines Corp., 2004
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
** the GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
**
**
**
** FILE : testfileperms.c
**
** PURPOSE: The purpose of this test is to verify the file permissions
** of all files under a given directory. The test makes 2 passes
** through all the files.
** Pass 1:
** Using the existing file attributes, verify file
** access as the file owner, group owner and other.
** The results of "open" are used to determine access.
** If the file owner is root, it is expected that access
** will be granted even if permissions are explicitly
** denied.
** Pass 2:
** An attempt is made to chown the file to the provided
** testuser and testgroup.
** If the chown fails, a message is logged and the file
** is skipped.
** If the chown succeeds, a stat is performed to verify
** the chown was effective. If the file owner and group
** has not been modified, a message is logged and the file
** is skipped.
** Once the file is chowned, file permissions are verified
** as the testuser/testgroup.
**
** In all cases, links are skipped.
**
**
** HISTORY:
** 10/04 originated by Dan Jones (danjones(a)us.ibm.com)
** A1 11/18/04 Kris Wilson (krisw(a)us.ibm.com) If access is expected
** but denied, this is not a security problem, it is a
** problem if denial is expected but access allowed. So if
** pass is expected but fail received, this has been deemed
** OK for certification purposes.
**********************************************************************/
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include <errno.h>
extern int alphasort ();
static int perms[] = {S_IRUSR, S_IWUSR, S_IXUSR,
S_IRGRP, S_IWGRP, S_IXGRP,
S_IROTH, S_IWOTH, S_IXOTH};
static char *ptext[] = {"r", "w", "x", "r", "w", "x", "r", "w", "x"};
int totalpass = 0;
int totalfail = 0;
uid_t uid_nobody = 65534;
gid_t gid_nobody = 65533;
int test = 0;
static char *test_description[] = {"Check default permissions",
"chown files to testuser/testgroup"};
/*
* Do not include . or .. in directory list.
*/
int file_select (struct direct *entry)
{
if ((strcmp (entry->d_name, ".") == 0)
|| (strcmp (entry->d_name, "..") == 0))
return (0);
else
return (1);
}
/*
* Set euid, egid
*/
void setids(uid_t uid, gid_t gid) {
int rc = 0;
if ((rc = setegid(gid)) == -1)
printf("\nERROR: unable to set gid. errno = %d\n", errno);
if ((rc = seteuid(uid)) == -1)
printf("\nERROR: unable to set uid. errno = %d\n", errno);
return;
}
/*
* Check actual vs. expected access using open system call
*/
void testaccess(char *pathname, int mode, int expected, char *outbuf) {
int testrc = 0;
int myerr = 0;
if (expected == -1) {
strcat(outbuf, "expected: fail ");
} else {
strcat(outbuf, "expected: pass ");
}
if ((testrc = open(pathname, mode)) == -1) {
myerr = errno;
strcat(outbuf, "actual: fail");
} else {
strcat(outbuf, "actual: pass");
close(testrc);
}
if (myerr == ENODEV) {
sprintf(&(outbuf[strlen(outbuf)]), "\tresult: SKIP : no device : %s\n", pathname);
} else if (myerr == EBUSY) {
sprintf(&(outbuf[strlen(outbuf)]), "\tresult: SKIP : device busy : %s\n", pathname);
} else if ((testrc == expected) || ((expected == 0) && (testrc != -1))) {
strcat(outbuf, "\tresult: PASS\n");
totalpass++;
} else {
/* A1 OK if expected pass but got fail, but need to log so can manually check errno. */
if ((expected == 0) && (testrc == -1)) {
sprintf(&(outbuf[strlen(outbuf)]), "\tresult: FAIL/PASS : errno = %d : %s\n", errno, pathname);
totalpass++;
} else {
sprintf(&(outbuf[strlen(outbuf)]), "\tresult: FAIL : errno = %d : %s\n", errno, pathname);
totalfail++;
}
}
printf("%s", outbuf);
return;
}
/*
* Test access for owner, group, other
*/
void testall(struct stat *ostatbufp, char *pathname, uid_t uid, gid_t gid) {
int i;
int rc = 0;
char outbuf[256];
struct passwd passwd;
struct passwd *passwdp;
struct group group;
struct group *groupp;
struct stat statbuf;
struct stat *statbufp = &statbuf;
char *pbuf;
char *gbuf;
passwdp = (struct passwd *)malloc(sizeof(passwd));
groupp = (struct group *)malloc(sizeof(group));
pbuf = (char *)malloc(4096);
gbuf = (char *)malloc(4096);
memset(pbuf, '\0', 4096);
memset(gbuf, '\0', 4096);
setids(0,0);
printf("\n%s\n", pathname);
// For test 1 we chown the file owner/group
if (test == 1) {
if ((rc = chown(pathname, uid, gid)) == -1) {
printf("ERROR: unable to chown %s to %d:%d\n", pathname, uid, gid);
goto EXIT;
}
}
// Start with clean buffers
memset(&statbuf, '\0', sizeof(statbuf));
// Get file stat info to determine actual owner and group
stat(pathname, &statbuf);
// If we successfully chown'd the file, but the owner hasn't changed
// log it and skip.
if ((test == 1) && ((statbufp->st_uid != uid) || (statbufp->st_gid != gid))) {
printf("INFO: chown success, but file owner did not change: %s\n", pathname);
goto EXIT;
}
memset(outbuf, '\0', sizeof(outbuf));
strcat(outbuf, "MODE: ");
for (i = 0; i < sizeof(perms)/sizeof(int); i++) {
if (statbufp->st_mode & perms[i]) {
strcat(outbuf, ptext[i]);
} else {
strcat(outbuf, "-");
}
}
getpwuid_r(statbufp->st_uid, &passwd, pbuf, 4096, &passwdp);
getgrgid_r(statbufp->st_gid, &group, gbuf, 4096, &groupp);
sprintf(&(outbuf[strlen(outbuf)]), " %s:%s\n", passwd.pw_name, group.gr_name);
printf("%s", outbuf);
// Check owner access for read/write
setids(statbufp->st_uid, gid_nobody);
memset(outbuf, '\0', sizeof(outbuf));
strcat(outbuf, "Owner read\t");
// If we are root, we expect to succeed event
// without explicit permission.
if ((statbufp->st_mode & S_IRUSR) || (statbufp->st_uid == 0)) {
testaccess(pathname, O_RDONLY, 0, outbuf);
} else {
testaccess(pathname, O_RDONLY, -1, outbuf);
}
memset(outbuf, '\0', sizeof(outbuf));
strcat(outbuf, "Owner write\t");
// If we are root, we expect to succeed event
// without explicit permission.
if ((statbufp->st_mode & S_IWUSR) || (statbufp->st_uid == 0)) {
testaccess(pathname, O_WRONLY, 0, outbuf);
} else {
testaccess(pathname, O_WRONLY, -1, outbuf);
}
// Check group access for read/write
setids(0, 0);
setids(uid_nobody, statbufp->st_gid);
memset(outbuf, '\0', sizeof(outbuf));
strcat(outbuf, "Group read\t");
if (statbufp->st_mode & S_IRGRP) {
testaccess(pathname, O_RDONLY, 0, outbuf);
} else {
testaccess(pathname, O_RDONLY, -1, outbuf);
}
memset(outbuf, '\0', sizeof(outbuf));
strcat(outbuf, "Group write\t");
if (statbufp->st_mode & S_IWGRP) {
testaccess(pathname, O_WRONLY, 0, outbuf);
} else {
testaccess(pathname, O_WRONLY, -1, outbuf);
}
// Check other access for read/write
setids(0, 0);
setids(uid_nobody, gid_nobody);
memset(outbuf, '\0', sizeof(outbuf));
strcat(outbuf, "Other read\t");
if (statbufp->st_mode & S_IROTH) {
testaccess(pathname, O_RDONLY, 0, outbuf);
} else {
testaccess(pathname, O_RDONLY, -1, outbuf);
}
memset(outbuf, '\0', sizeof(outbuf));
strcat(outbuf, "Other write\t");
if (statbufp->st_mode & S_IWOTH) {
testaccess(pathname, O_WRONLY, 0, outbuf);
} else {
testaccess(pathname, O_WRONLY, -1, outbuf);
}
setids(0, 0);
if (test == 1) {
chown(pathname, ostatbufp->st_uid, ostatbufp->st_gid);
}
EXIT:
return;
}
/*
* Check access.
*
* This method check a file or recursively scan directories and verify
* the file access modes are enforced.
*
*/
void check_access (char *pathname, uid_t uid, gid_t gid)
{
int count = 0;
int i = 0;
int rc = 0;
int file_select ();
char entry[MAXPATHLEN];
struct dirent **entries;
struct stat statbuf;
// Start with clean buffers
memset(&statbuf, '\0', sizeof(statbuf));
// Get file stat info.
if ((rc = lstat(pathname, &statbuf)) == -1) {
printf("\nERROR: %s. Could not obtain file status. errno = %d\n", pathname, errno);
goto EXIT;
}
// If link, skip it.
if (S_ISLNK(statbuf.st_mode)) {
printf("Link: skipping %s\n", entry);
goto EXIT;
}
// If not a directory, check it and leave.
if (!(S_ISDIR(statbuf.st_mode))) {
testall(&statbuf, pathname, uid, gid);
goto EXIT;
}
// If directory, recurse through all subdirectories, checking all files.
if ((count = scandir (pathname, &entries, file_select, alphasort)) == -1) {
printf("\nERROR: %s. Could not scandir. errno = %d\n", pathname, errno);
goto EXIT;
}
for (i = 0; i < count; i++) {
sprintf(entry, "%s/%s", pathname, entries[i]->d_name);
// If link, skip it
// Else if directory, call check_access() recursively
if (entries[i]->d_type == DT_LNK) {
printf("Link: skipping %s\n", entry);
continue;
} else if (entries[i]->d_type == DT_DIR) {
check_access(entry, uid, gid);
continue;
}
// Clean the buffer
memset(&statbuf, '\0', sizeof(statbuf));
// Get file stat info.
if ((rc = lstat(entry, &statbuf)) == -1) {
printf("\nERROR: %s. Could not obtain file status. errno = %d\n", pathname, errno);
continue;
}
// The directory entry doesn't always seem to have the
// right info. So we check again after the stat().
//
// If link, skip it
// Else if directory, call check_access() recursively
// Else check access
if (S_ISLNK(statbuf.st_mode)) {
printf("Link: (2) skipping %s\n", entry);
continue;
} else if (S_ISDIR(statbuf.st_mode)) {
check_access(entry, uid, gid);
continue;
} else {
testall(&statbuf, entry, uid, gid);
continue;
}
}
EXIT:
return;
}
int main (int argc, char *argv[]) {
int i = 0;
struct passwd *pw;
struct group *gr;
if (argc != 4) {
printf("usage: checkchown <directory> <testuser> <testgroup>\n");
goto EXIT;
}
if ((pw = getpwnam(argv[2])) == NULL) {
printf("ERROR: invalid username %s\n", argv[2]);
goto EXIT;
}
if ((gr = getgrnam(argv[3])) == NULL) {
printf("ERROR: invalid group %s\n", argv[3]);
goto EXIT;
}
for (i = 0; i < 2; i++) {
totalpass = 0;
totalfail = 0;
test = i;
printf("Test: %s\n\n", test_description[i]);
check_access(argv[1], pw->pw_uid, gr->gr_gid);
printf("\nPASS = %d, FAIL = %d\n\n", totalpass, totalfail);
}
EXIT:
return (0);
}
19 years, 5 months
audit 0.9.17 released
by Steve Grubb
Hi,
I've just released a new version of the audit daemon. It can be downloaded
from http://people.redhat.com/sgrubb/audit It will also be in rawhide
tomorrow. The Changelog is:
- Fix ausearch buffers to hold long filenames
- Make a0 long long for 64 bit kernels & 32 bit ausearch.
This is a bug fix release. The a0 variable is saved away by ausearch to
identify socketcall's actual multiplexed call. (bind, connect, etc). It was
getting 10 byte long hex numbers rather than 8 byte when 64 bit kernel was
used and user space ausearch was compiled for 32 bits. This caused it to skip
the event as it was considered corrupted.
Please let me know if there are any problems.
-Steve
19 years, 5 months
audit 0.9.16 released
by Steve Grubb
Hi,
I've just released a new version of the audit daemon. It can be downloaded
from http://people.redhat.com/sgrubb/audit It will also be in rawhide
tomorrow. The Changelog is:
- Adjust umask
- Adjust length of strings for file system watches to not include NUL
- Remove extra error message from audit_send
This release also cleans up messages output for people that do not have file
system auditing in their kernel. Please let me know if there are any
problems.
-Steve
19 years, 5 months
[RFC/PATCH 0/2] fsnotify/inotify split
by Chris Wright
The following two patches simply split fsnotify from inotify.
There should be no functional change to inotify at all. Perhaps the
split will help identify the interface bits that can easily converge
for inotify and audit. They're completely untested... I started with
inotify-45 in 2.6.13-rc2-mm1, and worked against base 2.6.13-rc2.
My first pass was trivial split, this is my second pass which moves
dnotify and inotify functionality out of fsnotify.h into their respective
corners. I'm sure audit can at least use the hooks, and perhaps more
base inode watch functionality could be shared (at no cost to you! ;-)
moving forward.
thanks,
-chris
19 years, 5 months