Fwd: Reporting some Kernel Panics
Jeff Burke
jburke at redhat.com
Mon Jul 11 15:01:31 UTC 2005
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 at 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 at us.ibm.com)
>** A1 11/18/04 Kris Wilson (krisw at 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
More information about the Linux-audit
mailing list