[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: Fwd: Reporting some Kernel Panics



Linda Knippers wrote:

I can write a test that will try and read all files in /proc. May or may not provide
any data.


Attached is the test program they were running.  Kris Wilson sent it
to me.  I've tried it a few times on an ia64 system with the .74 kernel
but haven't seen any problems.  Maybe you'll have better luck.

-- ljk

------------------------------------------------------------------------

##########################################################################
# 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 : Makefile
#
# PURPOSE: The default "all" target uses the gcc compiler to compile all
# test files in the current directory.
#
# The "clean" target removes all files the end in ".o" (object
# files).
#
#
# HISTORY:
# 10/04 originated by Dan Jones (danjones us ibm com)
#
##########################################################################
TOPDIR= ../..
LOG=log
CC=gcc EXE=testfileperms
DIRS= proc \
sys


all:: $(EXE)

run:: all
	-grep "^fpermu" /etc/passwd | awk -F: '{print $$1}' | xargs -i userdel -r {}
	-grep "^fpermg" /etc/group | awk -F: '{print $$1}' | xargs -i groupdel {}
	useradd fpermu &>/dev/null
	groupadd fpermg &>/dev/null
	-for i in $(DIRS); do ./$(EXE) /$$i fpermu fpermg &>$(EXE).$$i.$(LOG); done
	-for i in $(DIRS); do grep "FAIL" $(EXE).$$i.$(LOG) > $(EXE).$$i.FAIL; done
	-for i in $(DIRS); do grep "SKIP" $(EXE).$$i.$(LOG) > $(EXE).$$i.SKIP; done

	groupdel fpermg &>/dev/null
	userdel -fr fpermu &>/dev/null

rmlogs::
	rm -f *log &>/dev/null
	rm -f *FAIL &>/dev/null
	rm -f *SKIP &>/dev/null

clean::
	rm -f $(EXE)

# include $(TOPDIR)/rules.mk


------------------------------------------------------------------------

/**********************************************************************
** 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 us ibm com)
** A1 11/18/04 Kris Wilson (krisw 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);
}




Linda,
   Is this test out of the additions to the LTP test suite for audit?

Thanks,
Jeff


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]