This was handled by sysctl but not sysctlbyname.
The value returned was wrong.
Added a regtest.
/none/tests/freebsd/fexecve
/none/tests/freebsd/hello_world
/none/tests/freebsd/452275
+/none/tests/freebsd/usrstack
# /none/tests/x86/
/none/tests/x86/*.dSYM
Word VG_(get_usrstack)(void)
{
- return VG_PGROUNDDN(the_iicii.clstack_end - the_iifii.clstack_max_size);
+ return VG_PGROUNDDN(the_iicii.clstack_end) + VKI_PAGE_SIZE;
}
return False;
}
+static void sysctl_kern_usrstack(SizeT* out, SizeT* outlen)
+{
+ *out = VG_(get_usrstack)();
+ *outlen = sizeof(ULong);
+}
+
// SYS___sysctl 202
/* int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); */
/* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 */
if (SARG2 >= 2 && ML_(safe_to_deref)(name, 2*sizeof(int))) {
if (name[0] == 1 && name[1] == 33) {
// kern.userstack
- Word tmp = VG_(get_usrstack)();
- size_t* out = (size_t*)ARG3;
- size_t* outlen = (size_t*)ARG4;
- *out = tmp;
- *outlen = sizeof(ULong);
+ sysctl_kern_usrstack((size_t*)ARG3, (size_t*)ARG4);
SET_STATUS_Success(0);
}
}
if (ML_(safe_to_deref)(name, sizeof("kern.ps_strings")) &&
VG_(strcmp)(name, "kern.ps_strings") == 0) {
if (sysctl_kern_ps_strings((SizeT*)ARG3, (SizeT*)ARG4)) {
- SET_STATUS_Success(0);
+ SET_STATUS_Success(0);
}
}
+ if (ML_(safe_to_deref)(name, sizeof("kern.usrstack")) &&
+ VG_(strcmp)(name, "kern.usrstack") == 0) {
+ sysctl_kern_usrstack((size_t*)ARG3, (size_t*)ARG4);
+ SET_STATUS_Success(0);
+ }
+
// read number of ints specified in ARG2 from mem pointed to by ARG1
PRE_MEM_READ("__sysctlbyname(name)", (Addr)ARG1, ARG2 * sizeof(int));
fexecve_txt.vgtest \
fexecve_txt.stderr.exp \
452275.vgtest \
- 452275.stderr.exp
+ 452275.stderr.exp \
+ usrstack.vgtest \
+ usrstack.stderr.exp \
+ usrstack.stdout.exp
check_PROGRAMS = \
- auxv osrel swapcontext hello_world fexecve 452275
+ auxv osrel swapcontext hello_world fexecve 452275 usrstack
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
--- /dev/null
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void)
+{
+ int stack_variable = 1;
+ unsigned long v1;
+ unsigned long v2;
+ int name[] = {CTL_KERN, KERN_USRSTACK};
+ size_t len = sizeof(unsigned long);
+
+ if (sysctlbyname("kern.usrstack", &v1, &len, NULL, 0) < 0) {
+ perror("sysctlbyname failed:");
+ exit(-1);
+ }
+
+ if (sysctl(name, 2, &v2, &len, NULL, 0) < 0) {
+ perror("sysctl failed:");
+ exit(-1);
+ }
+
+ if (v1 == v2) {
+ printf("OK 1\n");
+ } else {
+ printf("FAIL usrstack different\n");
+ printf("v1 %lx v2 %lx\n", v1, v2);
+ }
+
+
+ /* the purpose of this is to check that the sysctl isn't
+ returning the host stack. I expec the difference to be less than 0x1000 */
+ if (v1 - (unsigned long)&stack_variable > 0x2000U) {
+ printf("FAIL usrstack fishy\n");
+ printf("v1 %lx stack_variable %p diff %lx\n", v1, &stack_variable, v1 - (unsigned long)&stack_variable);
+ } else {
+ printf("OK 2\n");
+ }
+}
+
--- /dev/null
+OK 1
+OK 2
--- /dev/null
+prog: usrstack
+vgopts: -q
+