[This commit is taken from commits 6391, 6401, and 6402 of the internal tree.]

tonyj:
- Verify long path (d_path) error checking. (6391)
- Better ptrace tests. (6401)
- Confined mount tests require cap_sys_admin to even get to the confined
  checks. (6402)
This commit is contained in:
Steve Beattie 2006-05-19 16:50:17 +00:00
parent 6fda1df1a6
commit 92c9c8732d
6 changed files with 537 additions and 36 deletions

View file

@ -7,17 +7,54 @@
# published by the Free Software Foundation, version 2 of the # published by the Free Software Foundation, version 2 of the
# License. # License.
SRC=access.c changehat.c changehat_fork.c changehat_misc.c changehat_misc2.c \ SRC=access.c \
changehat_twice.c changehat_fail.c changehat_wrapper.c changehat_pthread.c \ changehat.c \
chdir.c chgrp.c chmod.c chown.c \ changehat_fork.c \
exec.c exec_qual.c exec_qual2.c fork.c link.c mmap.c \ changehat_misc.c \
mkdir.c mount.c named_pipe.c net_raw.c open.c pipe.c pwrite.c rename.c \ changehat_misc2.c \
readdir.c rw.c syscall_mknod.c swap.c syscall_chroot.c \ changehat_twice.c \
changehat_fail.c \
changehat_wrapper.c \
changehat_pthread.c \
chdir.c \
chgrp.c \
chmod.c \
chown.c \
deleted.c \
exec.c \
exec_qual.c \
exec_qual2.c \
fork.c \
link.c \
mmap.c \
mkdir.c \
mount.c \
named_pipe.c \
net_raw.c \
open.c \
pipe.c \
ptrace.c \
ptrace_helper.c \
pwrite.c \
rename.c \
readdir.c \
rw.c \
syscall_mknod.c \
swap.c \
syscall_chroot.c \
syscall_mlockall.c \ syscall_mlockall.c \
syscall_ptrace.c syscall_reboot.c syscall_setpriority.c \ syscall_ptrace.c \
syscall_sethostname.c syscall_setdomainname.c syscall_setscheduler.c \ syscall_reboot.c \
syscall_sysctl.c tcp.c unix_fd_client.c unix_fd_server.c unlink.c \ syscall_setpriority.c \
deleted.c xattrs.c syscall_sethostname.c \
syscall_setdomainname.c \
syscall_setscheduler.c \
syscall_sysctl.c \
tcp.c \
unix_fd_client.c \
unix_fd_server.c \
unlink.c \
xattrs.c
#only do the ioperm/iopl tests for x86 derived architectures #only do the ioperm/iopl tests for x86 derived architectures
ifneq (,$(findstring $(shell uname -i),i386 i486 i586 i686 x86 x86_64)) ifneq (,$(findstring $(shell uname -i),i386 i486 i586 i686 x86 x86_64))
@ -56,10 +93,38 @@ CFLAGS+=$(CHANGEHAT_FLAGS) $(LIBIMMUNIX) -Wall -Wstrict-prototypes
EXEC=$(SRC:%.c=%) EXEC=$(SRC:%.c=%)
TESTS=access capabilities changehat changehat_fork changehat_misc chdir exec \ TESTS=access \
exec_qual fork i18n link mkdir mmap mount mult_mount named_pipe net_raw \ capabilities \
open pipe ptrace pwrite regex rename readdir rw swap sd_flags setattr \ changehat \
syscall unix_fd_server unlink deleted xattrs changehat_fork \
changehat_misc \
chdir \
deleted \
exec \
exec_qual \
fork \
i18n \
link \
mkdir \
mmap \
mount \
mult_mount \
named_pipe \
net_raw \
open pipe \
ptrace \
pwrite \
regex \
rename \
readdir \
rw \
swap \
sd_flags \
setattr \
syscall \
unix_fd_server \
unlink\
xattrs
all: $(EXEC) changehat.h all: $(EXEC) changehat.h
# This is sadly needed for buildbot, which has a restrictive umask. # This is sadly needed for buildbot, which has a restrictive umask.
@ -68,6 +133,9 @@ all: $(EXEC) changehat.h
changehat_pthread: changehat_pthread.c changehat.h changehat_pthread: changehat_pthread.c changehat.h
${CC} ${CFLAGS} -lpthread -o $@ $< ${CC} ${CFLAGS} -lpthread -o $@ $<
ptrace_helper: ptrace_helper.c
$(CC) -o $@ $<
tests: all tests: all
@if [ `whoami` == "root" ] ;\ @if [ `whoami` == "root" ] ;\
then \ then \

View file

@ -0,0 +1,169 @@
#! /bin/bash
# $Id: open.sh 6040 2006-01-11 00:15:48Z tonyj $
# Copyright (C) 2002-2005 Novell/SUSE
#
# 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, version 2 of the
# License.
#=NAME longpath
#=DESCRIPTION
# Verify handling of long pathnames.
#=END
genrandname()
{
_goal=$1
_ascii="abcdefghijlkmnopqrstuvwxyz0123456789"
_mod=${#_ascii}
_i=0
for _i in `seq 2 $_goal`
do
_c=$((RANDOM % $_mod))
_s="${_s}${_ascii:$_c:1}"
done
echo $_s
}
pwd=`dirname $0`
pwd=`cd $pwd ; /bin/pwd`
bin=$pwd
. $bin/prologue.inc
name_max=255 #NAME_MAX
direlem_max=235 #Length for intermediate dirs, slightly less than name_max
buf_max=4096 #PAGE
# generate 255 character filename
file=`genrandname $name_max`
file2=`genrandname $name_max`
settest open
okperm=rw
linkperm=rwl
cd $tmpdir
mkdir_expected_fail=0
file_expected_fail=0
link_expected_fail=0
iter=1
while true
do
direlem=`genrandname $direlem_max`
_dpath=`pwd`/$direlem
if [ ${#_dpath} -lt 4096 ]
then
dstatus=pass
else
dstatus=fail
fi
settest mkdir
genprofile $tmpdir/**:$okperm
runchecktest "LONGPATH MKDIR ($iter)" $dstatus mkdir $direlem
if [ $dstatus = "pass" ]
then
if [ -d $direlem ]
then
#echo "mkdir ($iter) passed at length ${#_dpath}"
cd $direlem
else
echo "FAIL: $direlem ($_iter) was not created" >&2
fi
else
if [ -d $direlem ]
then
echo "mkdir ($iter) incorrectly generated dir at length ${#_dpath}"
else
#echo "mkdir ($iter) failed at length ${#_dpath}"
mkdir_expected_fail=1
fi
:
fi
_fpath=`pwd`/$file
if [ ${#_fpath} -lt 4096 ]
then
fstatus=pass
else
fstatus=fail
fi
settest open
genprofile $tmpdir/**:$okperm
runchecktest "LONGPATH CREATE ($iter)" $fstatus $file
if [ $fstatus = "pass" ]
then
if [ -f $file ]
then
#echo "file creat ($iter) passed at length ${#_dpath}"
:
else
echo "FAIL: $file ($_iter) was not created" >&2
fi
elif [ $fstatus = "fail" ]
then
if [ -f $file ]
then
echo "file creat ($iter) incorrectly generated file at length ${#_fpath}"
else
#echo "file creat ($iter) failed at length ${#_fpath}"
file_expected_fail=1
fi
fi
settest link
genprofile $tmpdir/**:$linkperm
if [ -f $file ]
then
_f=$file
elif [ -f ../$file ]
then
_f=../$file
else
echo "unable to find file to link" >&2
exit 1
fi
runchecktest "LONGPATH LINK ($iter)" $fstatus $_f $file2
if [ $fstatus = "pass" ]
then
if [ -f $file2 ]
then
#echo "file link ($iter) passed at length ${#_dpath}"
:
else
echo "FAIL: $file2 ($_iter) was not linked" >&2
fi
elif [ $fstatus = "fail" ]
then
if [ -f $file2 ]
then
echo "file link ($iter) incorrectly generated file at length ${#_dpath}"
else
#echo "file link ($iter) failed at length ${#_fpath}"
link_expected_fail=1
fi
fi
if [ $mkdir_expected_fail -eq 1 -a \
$file_expected_fail -eq 1 -a \
$link_expected_fail -eq 1 ]
then
break
fi
: $((iter++))
done

View file

@ -65,7 +65,7 @@ runchecktest "UMOUNT (unconfined)" pass umount ${loop_device} ${mount_point}
# TEST A2. confine MOUNT # TEST A2. confine MOUNT
genprofile genprofile capability:sys_admin
runchecktest "MOUNT (confined)" fail mount ${loop_device} ${mount_point} runchecktest "MOUNT (confined)" fail mount ${loop_device} ${mount_point}
# TEST A3. confine UMOUNT # TEST A3. confine UMOUNT

View file

@ -0,0 +1,187 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <signal.h>
#include <sys/user.h>
#define NUM_CHLD_SYSCALLS 10
#define RET_FAILURE 0
#define RET_SUCCESS 1
#define RET_CHLD_SUCCESS 2
#define RET_CHLD_FAILURE 3
#define RET_CHLD_SIGNAL 4
#define PARENT_TRACE 0
#define CHILD_TRACE 1
#define HELPER_TRACE 2
extern char **environ;
int interp_status(int status)
{
int rc;
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == 0) {
rc = RET_CHLD_SUCCESS;
} else {
rc = RET_CHLD_FAILURE;
}
} else {
rc = RET_CHLD_SIGNAL;
}
return rc;
}
int do_parent(pid_t pid, int trace, int num_syscall)
{
struct user_regs_struct regs;
int status, i;
if (trace) {
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
perror("FAIL: parent ptrace(PTRACE_ATTACH) failed - ");
return 0;
}
/* this sends a child SIGSTOP */
}
while (wait(&status) != pid);
if (!WIFSTOPPED(status))
return interp_status(status);
for (i=0;i<num_syscall * 2;i++){
/* this will restart stopped child */
if (ptrace(PTRACE_SYSCALL, pid, NULL, 0) == -1) {
perror("FAIL: parent ptrace(PTRACE_SINGLESTEP) failed - ");
return RET_FAILURE;
}
while (wait(&status) != pid);
if (!WIFSTOPPED(status))
return interp_status(status);
memset(&regs, 0, sizeof(regs));
if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1) {
perror("FAIL: parent ptrace(PTRACE_GETREGS) failed - ");
return RET_FAILURE;
}
}
if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) {
perror("FAIL: parent ptrace(PTRACE_DETACH) failed - ");
return RET_FAILURE;
}
return RET_SUCCESS;
}
int do_child(char *argv[], int child_trace, int helper)
{
if (helper) {
if (child_trace) {
putenv("_tracer=child");
} else {
putenv("_tracer=parent");
}
} else {
if (child_trace) {
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) == -1){
perror("FAIL: child ptrace(PTRACE_TRACEME) failed - ");
return RET_FAILURE;
}
}
if (raise(SIGSTOP) != 0){
perror("FAIL: child SIGSTOP itself failed -");
return RET_FAILURE;
}
/* ok were stopped, wait for parent to trace (continue) us */
}
execve(argv[0], argv, environ);
perror("FAIL: child exec failed - ");
return RET_FAILURE;
}
int main(int argc, char *argv[])
{
pid_t pid;
int parent_trace = 1,
use_helper = 0,
num_syscall = NUM_CHLD_SYSCALLS,
opt;
const char *usage="usage: %s [-c] [-n #syscall] program [args ...]";
char **args;
opterr=0;
while (1) {
opt=getopt(argc, argv, "chn:");
if (opt == -1)
break;
switch (opt) {
case 'c': parent_trace = 0;
break;
case 'h': use_helper = 1;
break;
case 'n': num_syscall = atoi(optarg);
break;
default:
fprintf(stderr, usage, argv[0]);
break;
}
}
if (argc < 2) {
fprintf(stderr, usage, argv[0]);
return 1;
}
args=&argv[optind];
pid = fork();
if (pid > 0){ /*parent */
int stat, ret;
ret = do_parent(pid, parent_trace, num_syscall);
kill(pid, SIGKILL);
if (ret < RET_CHLD_SUCCESS) {
/* wait for child */
while (wait(&stat) != pid);
}
if (ret == RET_FAILURE) {
fprintf(stderr, "FAIL: parent failed\n");
} else if (ret == RET_CHLD_SUCCESS ||
(ret == RET_SUCCESS && WIFSIGNALED(stat) && WTERMSIG(stat) == SIGKILL)) {
printf("PASS\n");
return 0;
} else if (ret == RET_CHLD_SIGNAL) {
fprintf(stderr, "FAIL: child killed\n");
} else {
fprintf(stderr, "FAIL: child failed\n");
}
} else if (pid == 0) { /* child */
if (do_child(args, !parent_trace, use_helper))
return 0;
} else {
perror("FAIL: fork failed - ");
}
return 1;
}

View file

@ -1,5 +1,5 @@
#! /bin/bash #! /bin/bash
# $Id: ptrace.sh 6040 2006-01-11 00:15:48Z tonyj $ # $Id$
# Copyright (C) 2002-2005 Novell/SUSE # Copyright (C) 2002-2005 Novell/SUSE
# #
@ -10,10 +10,9 @@
#=NAME ptrace #=NAME ptrace
#=DESCRIPTION #=DESCRIPTION
# Read permission is required for a confined process to be able to be traced # Verify ptrace. The tracing process (attacher or parent of ptrace_me) may
# using ptrace. This test verifies this. Currently is it not functioning # not be confined.
# correctly. It stopped functioning correctly somewhere between 2.4.18 and #
# 2.4.20.
#=END #=END
pwd=`dirname $0` pwd=`dirname $0`
@ -23,26 +22,59 @@ bin=$pwd
. $bin/prologue.inc . $bin/prologue.inc
file=$tmpdir/file # Disabled tests:
traceperm=rix # Tests 3b and 4b
notraceperm=ix # Read permission was required for a confined process to be able to be traced
openperm=rw # using ptrace. This stopped being required or functioning correctly
# somewhere between 2.4.18 and 2.4.20.
#
# Tests 10 and 11
# Requires a patch which prevents confined traced task from attempting exec.
# Unsure of usefulness of this. We are concerned about confined task being
# the tracer not the tracee
touch $file # Test Matrix:
# 1. unconfined parent, unconfined child, parent attaches PASS
# 2. unconfined parent, unconfined child, child requests tracing PASS
# 3a. unconfined parent, confined child (r), parent attaches PASS
# 4a. unconfined parent, confined child (r), child requests tracing PASS
# 3b. unconfined parent, confined child (!r), parent attaches FAIL
# 4b. unconfined parent, confined child (!r), child requests tracing FAIL
# 5. confined parent, unconfined child, parent attaches FAIL
# 6. confined parent, unconfined child, child requests tracing FAIL
# 7. confined parent, confined child, parent attaches FAIL
# 8. confined parent, confined child, child requests tracing FAIL
# 9. unconfined traced task attempts exec PASS
# 10. confined traced task attempts exec unconfined FAIL
# 11. confined traced task attempts exec confined FAIL
# PASS TEST, no confinement helper=$pwd/ptrace_helper
settest open
runchecktest "STRACE OPEN (no confinement)" pass $file runchecktest "test 1" pass -n 100 /bin/true
runchecktest "test 2" pass -c -n 100 /bin/true
# PASS TEST, with rx confinement genprofile image=$helper
settest open "$bin/strace.sh {}" runchecktest "test 3a" pass -h -n 100 $helper
genprofile $test:$traceperm $file:$openperm runchecktest "test 4a" pass -h -n 100 -c $helper
runchecktest "STRACE OPEN ($traceperm confinement)" pass $file # lack of 'r' perm is currently not working
#genprofile image=ix$helper
#runchecktest "test 3b" pass -h -n 100 $helper
#runchecktest "test 4b" pass -h -n 100 -c $helper
# FAIL TEST, with x confinement genprofile $helper:ux
settest open "$bin/strace.sh {}" runchecktest "test 5" fail -h -n 100 $helper
genprofile $test:$notraceperm $file:$openperm runchecktest "test 6" fail -h -n 100 -c $helper
runchecktest "STRACE OPEN ($notraceperm confinement)" fail $file genprofile $helper:px -- image=$helper
runchecktest "test 7" fail -h -n 100 $helper
runchecktest "test 8" fail -h -n 100 -c $helper
genprofile image=/bin/true
runchecktest "test 9" pass -- /bin/bash -c /bin/true
#genprofile image=$helper /bin/true:ux
#runchecktest "test 10" fail -h -n 100 $helper /bin/true
#genprofile image=$helper /bin/true:rix
#runchecktest "test 11" fail -h -n 1000 $helper /bin/true

View file

@ -0,0 +1,45 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#define RET_FAILURE 0
int main(int argc, char *argv[])
{
char **args=&argv[1];
char *tracer = getenv("_tracer");
extern char **environ;
int child_traces;
if (tracer && strcmp(tracer, "parent") == 0) {
child_traces = 0;
} else if (tracer && strcmp(tracer, "child") == 0) {
child_traces = 1;
} else {
fprintf(stderr, "No/invalid _tracer in environ\n");
return RET_FAILURE;
}
if (child_traces == 1 &&
ptrace(PTRACE_TRACEME, 0, NULL, NULL) == -1){
perror("FAIL: child/helper ptrace(PTRACE_TRACEME) failed - ");
return RET_FAILURE;
}
if (raise(SIGSTOP) != 0){
perror("FAIL: child/helper SIGSTOP itself failed -");
return RET_FAILURE;
}
/* ok were stopped, wait for parent to trace (continue) us */
if (*args) {
execve(args[0], args, environ);
} else {
for (;;) kill(getpid(), 0);
}
return RET_FAILURE;
}