summaryrefslogtreecommitdiff
path: root/tests/test-syscalls.c
blob: be4df8c3aec7e493fdfe4b45220b672f643b7bea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 *  Copyright (C) 2024 Free Software Foundation
 *
 * 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 the program ; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <syscalls.h>
#include <testlib.h>

#include <mach/exception.h>
#include <mach/mig_errors.h>
#include <mach/vm_param.h>

#include <mach.user.h>
#include <mach_port.user.h>
#include <exc.server.h>


static struct {
  mach_port_t exception_port;
  mach_port_t thread;
  mach_port_t task;
  integer_t exception;
  integer_t code;
  integer_t subcode;
} last_exc;
kern_return_t catch_exception_raise(mach_port_t exception_port,
                                    mach_port_t thread, mach_port_t task,
                                    integer_t exception, integer_t code,
                                    long_integer_t subcode)
{
  printf("received catch_exception_raise(%u %u %u %d %d %d)\n",
         exception_port, thread, task, exception, code, subcode);
  last_exc.exception_port = exception_port;
  last_exc.thread = thread;
  last_exc.task = task;
  last_exc.exception = exception;
  last_exc.code = code;
  last_exc.subcode = subcode;
  return KERN_SUCCESS;
}

static char simple_request_data[PAGE_SIZE];
static char simple_reply_data[PAGE_SIZE];
int simple_msg_server(boolean_t (*demuxer) (mach_msg_header_t *request,
                                             mach_msg_header_t *reply),
                      mach_port_t rcv_port_name,
                      int num_msgs)
{
  int midx = 0, mok = 0;
  int ret;
  mig_reply_header_t *request = (mig_reply_header_t*)simple_request_data;
  mig_reply_header_t *reply = (mig_reply_header_t*)simple_reply_data;
  while ((midx - num_msgs) < 0)
    {
      ret = mach_msg(&request->Head, MACH_RCV_MSG, 0, PAGE_SIZE,
                     rcv_port_name, 0, MACH_PORT_NULL);
      switch (ret)
        {
        case MACH_MSG_SUCCESS:
          if ((*demuxer)(&request->Head, &reply->Head))
            mok++;  // TODO send reply
          else
            FAILURE("demuxer didn't handle the message");
          break;
        default:
          ASSERT_RET(ret, "receiving in msg_server");
          break;
        }
      midx++;
    }
  if (mok != midx)
    FAILURE("wrong number of message received");
  return mok != midx;
}


void test_syscall_bad_arg_on_stack(void *arg)
{
  /* mach_msg() has 7 arguments, so the last one should be always
     passed on the stack on x86. Here we make ESP/RSP point to the
     wrong place to test the access check */
#ifdef __x86_64__
  asm volatile("movq	$0x123,%rsp;"			\
               "movq	$-25,%rax;"                     \
               "syscall;"                               \
               );
#else
  asm volatile("mov	$0x123,%esp;"			\
               "mov	$-25,%eax;"                     \
               "lcall	$0x7,$0x0;"                     \
               );
#endif
  FAILURE("we shouldn't be here!");
}

void test_bad_syscall_num(void *arg)
{
#ifdef __x86_64__
  asm volatile("movq	$0x123456,%rax;"                \
               "syscall;"                               \
               );
#else
  asm volatile("mov	$0x123456,%eax;"                \
               "lcall	$0x7,$0x0;"                     \
               );
#endif
  FAILURE("we shouldn't be here!");
}


int main(int argc, char *argv[], int envc, char *envp[])
{
  int err;
  mach_port_t excp;

  err = mach_port_allocate(mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &excp);
  ASSERT_RET(err, "creating exception port");

  err = mach_port_insert_right(mach_task_self(), excp, excp,
                               MACH_MSG_TYPE_MAKE_SEND);
  ASSERT_RET(err, "inserting send right into exception port");

  err = task_set_special_port(mach_task_self(), TASK_EXCEPTION_PORT, excp);
  ASSERT_RET(err, "setting task exception port");

  /* FIXME: receiving an exception with small size causes GP on 64 bit userspace */
  /* mig_reply_header_t msg; */
  /* err = mach_msg(&msg.Head,	/\* The header *\/ */
  /*                MACH_RCV_MSG, */
  /*                0, */
  /*                sizeof (msg),	/\* Max receive Size *\/ */
  /*                excp, */
  /*                1000, */
  /*                MACH_PORT_NULL); */

  // FIXME: maybe MIG should provide this prototype?
  boolean_t exc_server
    (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);

  memset(&last_exc, 0, sizeof(last_exc));
  test_thread_start(mach_task_self(), test_bad_syscall_num, NULL);
  ASSERT_RET(simple_msg_server(exc_server, excp, 1), "error in exc server");
  ASSERT((last_exc.exception == EXC_BAD_INSTRUCTION) && (last_exc.code == EXC_I386_INVOP),
         "bad exception for test_bad_syscall_num()");

  memset(&last_exc, 0, sizeof(last_exc));
  test_thread_start(mach_task_self(), test_syscall_bad_arg_on_stack, NULL);
  ASSERT_RET(simple_msg_server(exc_server, excp, 1), "error in exc server");
  ASSERT((last_exc.exception == EXC_BAD_ACCESS) && (last_exc.code == KERN_INVALID_ADDRESS),
         "bad exception for test_syscall_bad_arg_on_stack()");

  return 0;
}