#include <sys/msg.h> /* for message queue tests */
#include <sys/syscall.h> /* for get / settid */
#include <sys/sysctl.h> /* for determining hw */
+#include <sys/kas_info.h> /* for kas_info() */
#include <AvailabilityMacros.h> /* for determination of Mac OS X version (tiger, leopard, etc.) */
#include <libkern/OSByteOrder.h> /* for OSSwap32() */
#include <mach/mach.h>
+
extern char g_target_path[ PATH_MAX ];
extern int g_skip_setuid_tests;
-extern int g_is_under_rosetta;
extern int g_is_single_user;
*/
int access_chmod_fchmod_test( void * the_argp )
{
- int my_err;
- int my_fd = -1;
+ int error_occurred;
+ int my_err;
+ int my_fd = -1;
+
char * my_pathp = NULL;
- struct stat my_sb;
- kern_return_t my_kr;
+
+ uid_t euid,ruid;
+ struct stat my_sb;
+
+ FILE * file_handle;
+
+ kern_return_t my_kr;
+
my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_pathp, PATH_MAX, VM_FLAGS_ANYWHERE);
if(my_kr != KERN_SUCCESS){
goto test_failed_exit;
}
+
/* test chmod */
my_err = chmod( my_pathp, S_IRWXU );
if ( my_err == -1 ) {
/* special case when running as root - we get back EPERM when running as root */
my_err = errno;
-#if !TARGET_OS_EMBEDDED
if ( ( tmp == 0 && my_err != EPERM) || (tmp != 0 && my_err != EACCES) ) {
printf( "access failed with errno %d - %s. \n", my_err, strerror( my_err ) );
goto test_failed_exit;
}
-#else
- if ( ( tmp == 0 && my_err != EACCES) || (tmp != 0 && my_err != EACCES) ) {
- printf( "access failed with errno %d - %s. \n", my_err, strerror( my_err ) );
- goto test_failed_exit;
- }
-#endif
}
/* verify correct modes are set */
printf( "chmod call appears to have failed. stat shows incorrect values in st_mode! \n" );
goto test_failed_exit;
}
+
+
+ /* another test for the access system call -- refer ro radar# 6725311 */
+
+#if !TARGET_OS_EMBEDDED
+
+ /*
+ * This test makes sure that the access system call does not give the current user extra
+ * permissions on files the current user does not own. From radar #6725311, this could
+ * happen when the current user calls access() on a file owned by the current user in
+ * the same directory as the other files not owned by the current user.
+ *
+ * Note: This test expects that the effective uid (euid) is set to root.
+ *
+ */
+
+ /* Create a file that root owns */
+ file_handle = fopen(FILE_NOTME, "w");
+ fclose(file_handle);
+
+ /* Currently running as root (through setreuid manipulation), switch to running as the current user. */
+ euid = geteuid();
+ ruid = getuid();
+ setreuid(ruid, ruid);
+
+ /* Create a file that the current user owns */
+ file_handle = fopen(FILE_ME, "w");
+ fclose(file_handle);
+
+ error_occurred = 0;
+
+ /* Try to remove the file owned by root (this should fail). */
+ my_err = unlink(FILE_NOTME);
+
+ if (my_err < 0) {
+ my_err = errno;
+ }
+
+ if (my_err == 0) {
+ printf("Unresolved: First attempt deleted '" FILE_NOTME "'! \n");
+ error_occurred = 1;
+ } else {
+ printf("Status: First attempt to delete '" FILE_NOTME "' failed with error %d - %s.\n", my_err, strerror( my_err ));
+
+ /* Set _DELETE_OK on a file that the current user owns */
+ access(FILE_ME, _DELETE_OK);
+
+ /* Try to remove the file owned by root again (should give us: EPERM [13]) */
+ my_err = unlink(FILE_NOTME);
+
+ if (my_err < 0) {
+ my_err = errno;
+ }
+
+ if (my_err == 0) {
+ printf("Failed: Second attempt deleted '" FILE_NOTME "'!\n");
+ error_occurred = 1;
+ } else if (my_err == 13) {
+ printf("Passed: Second attempt to delete '" FILE_NOTME "' failed with error %d - %s.\n", my_err, strerror( my_err ));
+ } else {
+ printf("Failed: Second attempt to delete '" FILE_NOTME "' failed with error %d - %s.\n", my_err, strerror( my_err ));
+ error_occurred = 1;
+ }
+ }
+
+ /* Reset to running as root */
+ setreuid(ruid, euid);
+
+ if(error_occurred == 1) {
+ goto test_failed_exit;
+ }
+#endif
+
+ /* end of test*/
+
+
/* test fchmod */
my_fd = open( my_pathp, O_RDONLY, 0 );
if ( my_fd == -1 ) {
return( my_err );
}
+#if !TARGET_OS_EMBEDDED
+static bool _prime_groups(void)
+{
+ /*
+ * prime groups with a known list to ensure consistent test behavior
+ */
+
+ gid_t my_exp_groups[] = { getegid(), 20, 61, 12 };
+ int my_err;
+
+ my_err = setgroups( ( sizeof(my_exp_groups) / sizeof(*my_exp_groups) ), &my_exp_groups[0] );
+ if ( my_err == -1 ) {
+ printf( "initial setgroups call failed. got errno %d - %s. \n", errno, strerror( errno ) );
+ return false;
+ }
+
+ return true;
+}
+#endif
+
/* **************************************************************************************************************
* Test chown, fchown, lchown, lstat, readlink, symlink system calls.
* **************************************************************************************************************
goto test_failed_exit;
}
+ if ( !_prime_groups() ) {
+ goto test_failed_exit;
+ }
+
/* set up by getting a list of groups */
my_group_count = getgroups( NGROUPS_MAX, &my_groups[0] );
#pragma pack()
typedef struct vol_attr_buf vol_attr_buf;
+#define STATFS_TEST_PATH "/tmp"
+
int fs_stat_tests( void * the_argp )
{
int my_err, my_count, i;
}
my_statfsp = (struct statfs *) my_bufferp;
- my_err = statfs( "/", my_statfsp );
+ my_err = statfs( STATFS_TEST_PATH, my_statfsp );
if ( my_err == -1 ) {
printf( "statfs call failed. got errno %d - %s. \n", errno, strerror( errno ) );
goto test_failed_exit;
#if !TARGET_OS_EMBEDDED
/* now try statfs64 */
my_statfs64p = (struct statfs64 *) my_buffer64p;
- my_err = statfs64( "/", my_statfs64p );
+ my_err = statfs64( STATFS_TEST_PATH, my_statfs64p );
if ( my_err == -1 ) {
printf( "statfs64 call failed. got errno %d - %s. \n", errno, strerror( errno ) );
goto test_failed_exit;
}
}
- /* open kernel to use as test file for fstatfs */
- my_fd = open( "/mach_kernel", O_RDONLY, 0 );
+ /* open to use as test file for fstatfs */
+ my_fd = open( STATFS_TEST_PATH, O_RDONLY, 0 );
if ( my_fd == -1 ) {
printf( "open call failed. got errno %d - %s. \n", errno, strerror( errno ) );
goto test_failed_exit;
}
/* try again with statfs */
- my_err = statfs( "/mach_kernel", my_statfsp );
+ my_err = statfs( STATFS_TEST_PATH , my_statfsp );
if ( my_err == -1 ) {
printf( "statfs call failed. got errno %d - %s. \n", errno, strerror( errno ) );
goto test_failed_exit;
}
if (get_architecture() == INTEL) {
- int ppc_fail_flag = 0;
struct stat sb;
- if (stat("/usr/libexec/oah/translate", &sb))
- ppc_fail_flag = 1;
-
if (bits == 64 && sizeof(long) == 8) {
/*
* Running on x86_64 hardware and running in 64-bit mode.
argvs[0] = "launch-i386";
if (do_execve_test("helpers/launch-i386", argvs, NULL, 1) != 0) goto test_failed_exit;
- /* Test posix_spawn for i386, x86_64, and ppc (should succeed) */
+ /* Test posix_spawn for i386, x86_64 (should succeed) */
errmsg = NULL;
if (do_spawn_test(CPU_TYPE_I386, 0))
goto test_failed_exit;
if (do_spawn_test(CPU_TYPE_X86_64, 0))
goto test_failed_exit;
- /*
- * Note: rosetta is no go in single-user mode
- */
- if (!g_is_single_user) {
- if (do_spawn_test(CPU_TYPE_POWERPC, ppc_fail_flag))
- goto test_failed_exit;
- }
}
else if (bits == 64 && sizeof(long) == 4) {
/*
argvs[0] = "launch-x86_64";
if (do_execve_test("helpers/launch-x86_64", argvs, NULL, 1) != 0) goto test_failed_exit;
- /* Test posix_spawn for i386, x86_64, and ppc (should succeed) */
+ /* Test posix_spawn for i386, x86_64 (should succeed) */
errmsg = NULL;
if (do_spawn_test(CPU_TYPE_I386, 0))
goto test_failed_exit;
if (do_spawn_test(CPU_TYPE_X86_64, 0))
goto test_failed_exit;
- /*
- * Note: rosetta is no go in single-user mode
- */
- if (!g_is_single_user) {
- if (do_spawn_test(CPU_TYPE_POWERPC, ppc_fail_flag))
- goto test_failed_exit;
- }
}
else if (bits == 32) {
/* Running on i386 hardware. Check cases 4. */
argvs[0] = "sleep-i386";
if (do_execve_test("helpers/sleep-i386", argvs, NULL, 1)) goto test_failed_exit;
- /* Test posix_spawn for x86_64 (should fail), i386, and ppc (should succeed) */
+ /* Test posix_spawn for x86_64 (should fail), i386 (should succeed) */
errmsg = NULL;
if (do_spawn_test(CPU_TYPE_X86_64, 1))
goto test_failed_exit;
if (do_spawn_test(CPU_TYPE_I386, 0))
goto test_failed_exit;
- /*
- * Note: rosetta is no go in single-user mode
- */
- if (!g_is_single_user) {
- if (do_spawn_test(CPU_TYPE_POWERPC, ppc_fail_flag))
- goto test_failed_exit;
- }
- }
- }
- else if (get_architecture() == POWERPC) {
- if (bits == 64 && sizeof(long) == 8) {
- /*
- * Running on PPC64 hardware and running in 64-bit mode.
- * No longer supported on SnowLeopard.
- */
- errmsg = "runnning ppc64 on snowleopard";
- goto test_failed_exit;
- }
- else if (bits == 64 && sizeof(long) == 4) {
- /*
- * Running as PPC on PPC64 hardware or under Rosetta on x86_64 hardware.
- * Check cases 4, 5, 6 and fork a child to check 1, 2, 3.
- */
- errmsg = "execve failed: from ppc forking and exec()ing ppc process.\n";
- argvs[0] = "sleep-ppc32";
- if (do_execve_test("helpers/sleep-ppc32", argvs, NULL, 0)) goto test_failed_exit;
-
- /* Test posix_spawn for i386 and ppc */
- errmsg = NULL;
- if (do_spawn_test(CPU_TYPE_I386, (g_is_under_rosetta ? 0 : 1)))
- goto test_failed_exit;
- if (do_spawn_test(CPU_TYPE_POWERPC, 0))
- goto test_failed_exit;
- }
- else if (bits == 32) {
- /* Running on ppc hardware. Check cases 4. */
- errmsg = "execve failed: from ppc forking and exec()ing 32 bit ppc process.\n";
- argvs[0] = "sleep-ppc32";
- if (do_execve_test("helpers/sleep-ppc32", argvs, NULL, 1)) goto test_failed_exit;
- /* Test posix_spawn for i386 (should fail) and ppc (should succeed) */
- errmsg = NULL;
- /* when under Rosetta, this process is CPU_TYPE_POWERPC, but the system should be able to run CPU_TYPE_I386 binaries */
- if (do_spawn_test(CPU_TYPE_I386, (g_is_under_rosetta ? 0 : 1)))
- goto test_failed_exit;
- if (do_spawn_test(CPU_TYPE_POWERPC, 0))
- goto test_failed_exit;
}
- }
- else if(get_architecture() == ARM) {
+ }else if(get_architecture() == ARM) {
if (bits == 32) {
/* Running on arm hardware. Check cases 2. */
my_real_gid = getgid( );
my_effective_gid = getegid( );
+ if ( !_prime_groups() ) {
+ goto test_failed_exit;
+ }
+
/* start by getting list of groups the current user belongs to */
my_orig_group_count = getgroups( NGROUPS_MAX, &my_groups[0] );
/* first letters in ac_comm should match the name of the executable */
if ( getuid( ) != my_acctp->ac_uid || getgid( ) != my_acctp->ac_gid ||
my_acctp->ac_comm[0] != 't' || my_acctp->ac_comm[1] != 'r' ) {
- if (g_is_under_rosetta) {
- // on x86 systems, data written by kernel to accounting info file is little endian;
- // but Rosetta processes expects it to be big endian; so swap the uid for our test
- if ( getuid( ) != OSSwapInt32(my_acctp->ac_uid) ||
- getgid( ) != OSSwapInt32(my_acctp->ac_gid) ||
- my_acctp->ac_comm[0] != 't' ||
- my_acctp->ac_comm[1] != 'r' ) {
- printf( "accounting data does not look correct under Rosetta:\n" );
- printf( "------------------------\n" );
- printf( "my_acctp->ac_uid = %lu (should be: %lu)\n",
- (unsigned long) OSSwapInt32( my_acctp->ac_uid ), (unsigned long) getuid() );
- printf( "my_acctp->ac_gid = %lu (should be: %lu)\n",
- (unsigned long) OSSwapInt32( my_acctp->ac_gid ), (unsigned long) getgid() );
-
- print_acct_debug_strings(my_acctp->ac_comm);
- }
- else {
- // is cool under Rosetta
- my_err = 0;
- goto test_passed_exit;
- }
- }
- else {
- printf( "accounting data does not look correct:\n" );
printf( "------------------------\n" );
printf( "my_acctp->ac_uid = %lu (should be: %lu)\n", (unsigned long) my_acctp->ac_uid, (unsigned long) getuid() );
printf( "my_acctp->ac_gid = %lu (should be: %lu)\n", (unsigned long) my_acctp->ac_gid, (unsigned long) getgid() );
print_acct_debug_strings(my_acctp->ac_comm);
- }
goto test_failed_exit;
}
{
int my_err, my_result, my_tmep;
int my_fd = -1;
+ int my_newfd = -1;
char * my_pathp = NULL;
kern_return_t my_kr;
printf( "fcntl - F_SETFD failed to set FD_CLOEXEC correctly!!! \n" );
goto test_failed_exit;
}
-
+
+ /* dup it to a new fd with FD_CLOEXEC forced on */
+
+ my_result = fcntl( my_fd, F_DUPFD_CLOEXEC, 0);
+ if ( my_result == -1 ) {
+ printf( "fcntl - F_DUPFD_CLOEXEC - failed with error %d - \"%s\" \n", errno, strerror( errno) );
+ goto test_failed_exit;
+ }
+ my_newfd = my_result;
+
+ /* check to see that it too is marked with FD_CLOEXEC */
+
+ my_result = fcntl( my_newfd, F_GETFD, 0);
+ if ( my_result == -1 ) {
+ printf( "fcntl - F_GETFD - failed with error %d - \"%s\" \n", errno, strerror( errno) );
+ goto test_failed_exit;
+ }
+ if ( (my_result & FD_CLOEXEC) == 0 ) {
+ printf( "fcntl - F_DUPFD_CLOEXEC failed to set FD_CLOEXEC!!! \n" );
+ goto test_failed_exit;
+ }
+
+ close( my_newfd );
+ my_newfd = -1;
+
+#if !TARGET_OS_EMBEDDED /* This section of the test is specific for the desktop platform, refer <rdar://problem/8850905>*/
+ /* While we're here, dup it via an open of /dev/fd/<fd> .. */
+
+ {
+ char devfdpath[PATH_MAX];
+
+ (void) snprintf( devfdpath, sizeof (devfdpath),
+ "/dev/fd/%u", my_fd );
+ my_result = open( devfdpath, O_RDONLY | O_CLOEXEC );
+ }
+ if ( my_result == -1 ) {
+ printf( "open call failed on /dev/fd/%u with error %d - \"%s\" \n", my_fd, errno, strerror( errno) );
+ goto test_failed_exit;
+ }
+ my_newfd = my_result;
+
+ /* check to see that it too is marked with FD_CLOEXEC */
+
+ my_result = fcntl( my_newfd, F_GETFD, 0);
+ if ( my_result == -1 ) {
+ printf( "fcntl - F_GETFD - failed with error %d - \"%s\" \n", errno, strerror( errno) );
+ goto test_failed_exit;
+ }
+ if ( (my_result & FD_CLOEXEC) == 0 ) {
+ printf( "fcntl - O_CLOEXEC open of /dev/fd/%u failed to set FD_CLOEXEC!!! \n", my_fd );
+ goto test_failed_exit;
+ }
+ close ( my_newfd );
+ my_newfd = -1;
+#endif
my_err = 0;
goto test_passed_exit;
my_err = -1;
test_passed_exit:
+ if ( my_newfd != -1)
+ close ( my_newfd );
if ( my_fd != -1 )
close( my_fd );
if ( my_pathp != NULL ) {
int searchfs_test( void * the_argp )
{
+#if !TARGET_OS_EMBEDDED
int my_err, my_items_found = 0, my_ebusy_count;
char * my_pathp = NULL;
unsigned long my_matches;
vm_deallocate(mach_task_self(), (vm_address_t)my_pathp, PATH_MAX);
}
return( my_err );
+#else
+ printf( "\t--> Not supported on EMBEDDED TARGET\n" );
+ return 0;
+#endif
}
*/
int aio_tests( void * the_argp )
{
-#if !TARGET_OS_EMBEDDED
int my_err, i;
char * my_pathp;
struct aiocb * my_aiocbp;
}
}
return( my_err );
-#else
- printf( "\t--> Not supported on EMBEDDED TARGET\n" );
- return 0;
-#endif
}
}
+
/* **************************************************************************************************************
* Test execution from data and stack areas.
* **************************************************************************************************************
{
int my_err = 0;
int arch, bits;
+ posix_spawnattr_t attrp;
+ char *argv[] = { "helpers/data_exec32nonxspawn", NULL };
+ int my_pid, my_status, ret;
+
if ((arch = get_architecture()) == -1) {
printf("data_exec_test: couldn't determine architecture\n");
goto test_failed_exit;
printf("data_exec-i386 failed\n");
goto test_failed_exit;
}
- }
-
- if (arch == POWERPC) {
- if (system("arch -arch ppc helpers/data_exec") != 0) {
- printf("data_exec-ppc failed\n");
+
+ posix_spawnattr_init(&attrp);
+ posix_spawnattr_setflags(&attrp, _POSIX_SPAWN_ALLOW_DATA_EXEC );
+ ret = posix_spawn(&my_pid, "helpers/data_exec32nonxspawn", NULL, &attrp, argv, NULL);
+ if (ret) {
+ printf("data_exec-i386 failed in posix_spawn %s\n", strerror(errno));
+ goto test_failed_exit;
+ }
+ ret = wait4(my_pid, &my_status, 0, NULL);
+ if (ret == -1) {
+ printf("data_exec-i386 wait4 failed with errno %d - %s\n", errno, strerror(errno));
+ goto test_failed_exit;
+ }
+ if (WEXITSTATUS(my_status) != 0) {
+ printf("data_exec-i386 _POSIX_SPAWN_ALLOW_DATA_EXEC failed\n");
goto test_failed_exit;
}
}
return my_err;
}
+/* **************************************************************************************************************
+ * Test KASLR-related functionality
+ * **************************************************************************************************************
+ */
+int kaslr_test( void * the_argp )
+{
+ int result = 0;
+ uint64_t slide = 0;
+ size_t size;
+ int slide_enabled;
+
+ size = sizeof(slide_enabled);
+ result = sysctlbyname("kern.slide", &slide_enabled, &size, NULL, 0);
+ if (result != 0) {
+ printf("sysctlbyname(\"kern.slide\") failed with errno %d\n", errno);
+ goto test_failed_exit;
+ }
+
+ /* Test positive case first */
+ size = sizeof(slide);
+ result = kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, &slide, &size);
+ if (result == 0) {
+ /* syscall supported, slide must be non-zero if running latest xnu and KASLR is enabled */
+ if (slide_enabled && (slide == 0)) {
+ printf("kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, &slide, &size) reported slide of 0x%016llx\n", slide);
+ goto test_failed_exit;
+ }
+ if (size != sizeof(slide)) {
+ printf("kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, &slide, &size) reported size of %lu\n", size);
+ goto test_failed_exit;
+ }
+ } else {
+ /* Only ENOTSUP is allowed. If so, assume all calls will be unsupported */
+ if (errno == ENOTSUP) {
+ return 0;
+ } else {
+ printf("kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, &slide, &size) returned unexpected errno (errno %d)\n", errno);
+ goto test_failed_exit;
+ }
+ }
+
+ /* Negative cases for expected failures */
+ size = sizeof(slide);
+ result = kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, NULL /* EFAULT */, &size);
+ if ((result == 0) || (errno != EFAULT)) {
+ printf("kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, NULL, &size) returned unexpected success or errno (result %d errno %d)\n", result, errno);
+ goto test_failed_exit;
+ }
+
+ size = sizeof(slide) + 1; /* EINVAL */
+ result = kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, NULL, &size);
+ if ((result == 0) || (errno != EINVAL)) {
+ printf("kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, NULL, &size+1) returned unexpected success or errno (result %d errno %d)\n", result, errno);
+ goto test_failed_exit;
+ }
+
+ result = kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, NULL /* EFAULT */, NULL /* EFAULT */);
+ if ((result == 0) || (errno != EFAULT)) {
+ printf("kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, NULL, NULL) returned unexpected success or errno (result %d errno %d)\n", result, errno);
+ goto test_failed_exit;
+ }
+
+ size = sizeof(slide);
+ result = kas_info(KAS_INFO_MAX_SELECTOR /* EINVAL */, &slide, &size);
+ if ((result == 0) || (errno != EINVAL)) {
+ printf("kas_info(KAS_INFO_MAX_SELECTOR, &slide, &size) returned unexpected success or errno (result %d errno %d)\n", result, errno);
+ goto test_failed_exit;
+ }
+
+ return 0;
+
+test_failed_exit:
+ return -1;
+}
#if TEST_SYSTEM_CALLS