|
From: <sv...@va...> - 2012-10-04 20:27:46
|
tom 2012-10-04 21:27:38 +0100 (Thu, 04 Oct 2012)
New Revision: 13019
Log:
Implement a fake /proc/self/auxv file for linux systems.
Patch from Mark Wielaard to fix BZ#253519.
Added files:
trunk/memcheck/tests/linux/proc-auxv.c
trunk/memcheck/tests/linux/proc-auxv.stderr.exp
trunk/memcheck/tests/linux/proc-auxv.vgtest
Modified files:
trunk/coregrind/m_clientstate.c
trunk/coregrind/m_main.c
trunk/coregrind/m_syswrap/syswrap-generic.c
trunk/coregrind/m_syswrap/syswrap-linux.c
trunk/coregrind/pub_core_clientstate.h
trunk/memcheck/tests/linux/Makefile.am
Modified: trunk/coregrind/m_syswrap/syswrap-linux.c (+16 -0)
===================================================================
--- trunk/coregrind/m_syswrap/syswrap-linux.c 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/coregrind/m_syswrap/syswrap-linux.c 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -3332,6 +3332,22 @@
return;
}
+ /* Do the same for /proc/self/auxv or /proc/<pid>/auxv case. */
+
+ VG_(sprintf)(name, "/proc/%d/auxv", VG_(getpid)());
+ if (ML_(safe_to_deref)( (void*)ARG2, 1 )
+ && (VG_(strcmp)((Char *)ARG2, name) == 0
+ || VG_(strcmp)((Char *)ARG2, "/proc/self/auxv") == 0)) {
+ sres = VG_(dup)( VG_(cl_auxv_fd) );
+ SET_STATUS_from_SysRes( sres );
+ if (!sr_isError(sres)) {
+ OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
+ if (off < 0)
+ SET_STATUS_Failure( VKI_EMFILE );
+ }
+ return;
+ }
+
/* Otherwise handle normally */
*flags |= SfMayBlock;
}
Added: trunk/memcheck/tests/linux/proc-auxv.stderr.exp (+2 -0)
===================================================================
--- trunk/memcheck/tests/linux/proc-auxv.stderr.exp 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/memcheck/tests/linux/proc-auxv.stderr.exp 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -0,0 +1,2 @@
+entries OK
+platform OK
Added: trunk/memcheck/tests/linux/proc-auxv.vgtest (+2 -0)
===================================================================
--- trunk/memcheck/tests/linux/proc-auxv.vgtest 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/memcheck/tests/linux/proc-auxv.vgtest 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -0,0 +1,2 @@
+prog: proc-auxv
+vgopts: -q
Added: trunk/memcheck/tests/linux/proc-auxv.c (+62 -0)
===================================================================
--- trunk/memcheck/tests/linux/proc-auxv.c 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/memcheck/tests/linux/proc-auxv.c 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -0,0 +1,62 @@
+#include <elf.h>
+#include <link.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int
+main (int argc, char **argv, char **envp)
+{
+ ElfW(auxv_t) auxv;
+ ElfW(auxv_t) *auxv_p;
+
+ void *entry0 = NULL;
+ void *entry1 = NULL;
+
+ char *platform0 = NULL;
+ char *platform1 = NULL;
+
+ // First try the "traditional" way.
+ while (*envp++ != NULL)
+ ; /* Skip, skip, skip... and after finding a NULL we have the auxv. */
+
+ for (auxv_p = (ElfW(auxv_t) *) envp;
+ auxv_p->a_type != AT_NULL;
+ auxv_p++)
+ {
+ if (auxv_p->a_type == AT_ENTRY)
+ entry0 = (void *) auxv_p->a_un.a_val;
+ if (auxv_p->a_type == AT_PLATFORM)
+ platform0 = strdup((char *) auxv_p->a_un.a_val);
+ }
+
+ // Now the /proc way as often used in libraries.
+ int fd = open("/proc/self/auxv", O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ while (read(fd, &auxv, sizeof(auxv)) == sizeof(auxv))
+ {
+ if (auxv.a_type == AT_ENTRY)
+ entry1 = (void *) auxv.a_un.a_val;
+ if (auxv.a_type == AT_PLATFORM)
+ platform1 = strdup((char *) auxv.a_un.a_val);
+ }
+ close(fd);
+
+ if (entry0 == entry1 && entry0 != NULL)
+ fprintf(stderr, "entries OK\n");
+
+ if (strcmp (platform0, platform1) == 0)
+ fprintf(stderr, "platform OK\n");
+
+ free (platform0);
+ free (platform1);
+
+ return 0;
+}
Modified: trunk/coregrind/pub_core_clientstate.h (+3 -0)
===================================================================
--- trunk/coregrind/pub_core_clientstate.h 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/coregrind/pub_core_clientstate.h 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -67,6 +67,9 @@
the file contents alive exactly until the process exits. */
extern Int VG_(cl_cmdline_fd);
+/* Same as above, but for /proc/<pid>/auxv. */
+extern Int VG_(cl_auxv_fd);
+
// Client's original rlimit data and rlimit stack
extern struct vki_rlimit VG_(client_rlimit_data);
extern struct vki_rlimit VG_(client_rlimit_stack);
Modified: trunk/coregrind/m_main.c (+35 -3)
===================================================================
--- trunk/coregrind/m_main.c 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/coregrind/m_main.c 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -1871,14 +1871,17 @@
setup_file_descriptors();
//--------------------------------------------------------------
- // create the fake /proc/<pid>/cmdline file and then unlink it,
- // but hold onto the fd, so we can hand it out to the client
- // when it tries to open /proc/<pid>/cmdline for itself.
+ // create fake /proc/<pid>/cmdline and /proc/<pid>/auxv files
+ // and then unlink them, but hold onto the fds, so we can handr
+ // them out to the client when it tries to open
+ // /proc/<pid>/cmdline or /proc/<pid>/auxv for itself.
// p: setup file descriptors
+ // p: ii_create_image for VG_(client_auxv) setup.
//--------------------------------------------------------------
#if !defined(VGO_linux)
// client shouldn't be using /proc!
VG_(cl_cmdline_fd) = -1;
+ VG_(cl_auxv_fd) = -1;
#else
if (!need_help) {
HChar buf[50], buf2[50+64];
@@ -1915,6 +1918,35 @@
VG_(err_config_error)("Can't delete client cmdline file in %s\n", buf2);
VG_(cl_cmdline_fd) = fd;
+
+ VG_(debugLog)(1, "main", "Create fake /proc/<pid>/auxv\n");
+
+ VG_(sprintf)(buf, "proc_%d_auxv", VG_(getpid)());
+ fd = VG_(mkstemp)( buf, buf2 );
+ if (fd == -1)
+ VG_(err_config_error)("Can't create client auxv file in %s\n", buf2);
+
+ UWord *client_auxv = VG_(client_auxv);
+ unsigned int client_auxv_len = 0;
+ while (*client_auxv != 0) {
+ client_auxv++;
+ client_auxv++;
+ client_auxv_len += 2 * sizeof(UWord);
+ }
+ client_auxv_len += 2 * sizeof(UWord);
+
+ VG_(write)(fd, VG_(client_auxv), client_auxv_len);
+
+ /* Don't bother to seek the file back to the start; instead do
+ it every time a copy of it is given out (by PRE(sys_open)).
+ That is probably more robust across fork() etc. */
+
+ /* Now delete it, but hang on to the fd. */
+ r = VG_(unlink)( buf2 );
+ if (r)
+ VG_(err_config_error)("Can't delete client auxv file in %s\n", buf2);
+
+ VG_(cl_auxv_fd) = fd;
}
#endif
Modified: trunk/coregrind/m_clientstate.c (+3 -0)
===================================================================
--- trunk/coregrind/m_clientstate.c 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/coregrind/m_clientstate.c 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -64,6 +64,9 @@
/* A fd which refers to the fake /proc/<pid>/cmdline in /tmp. */
Int VG_(cl_cmdline_fd) = -1;
+/* A fd which refers to the fake /proc/<pid>/auxv in /tmp. */
+Int VG_(cl_auxv_fd) = -1;
+
// Command line pieces, after they have been extracted from argv in
// m_main.main(). The payload vectors are allocated in VG_AR_TOOL
// (the default arena). They are never freed.
Modified: trunk/memcheck/tests/linux/Makefile.am (+4 -2)
===================================================================
--- trunk/memcheck/tests/linux/Makefile.am 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/memcheck/tests/linux/Makefile.am 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -15,7 +15,8 @@
syscalls-2007.vgtest syscalls-2007.stderr.exp \
syslog-syscall.vgtest syslog-syscall.stderr.exp \
timerfd-syscall.vgtest timerfd-syscall.stderr.exp \
- with-space.stderr.exp with-space.stdout.exp with-space.vgtest
+ with-space.stderr.exp with-space.stdout.exp with-space.vgtest \
+ proc-auxv.vgtest proc-auxv.stderr.exp
check_PROGRAMS = \
brk \
@@ -27,7 +28,8 @@
stack_switch \
syscalls-2007 \
syslog-syscall \
- timerfd-syscall
+ timerfd-syscall \
+ proc-auxv
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
Modified: trunk/coregrind/m_syswrap/syswrap-generic.c (+25 -0)
===================================================================
--- trunk/coregrind/m_syswrap/syswrap-generic.c 2012-10-04 21:01:50 +01:00 (rev 13018)
+++ trunk/coregrind/m_syswrap/syswrap-generic.c 2012-10-04 21:27:38 +01:00 (rev 13019)
@@ -3633,6 +3633,31 @@
return;
}
}
+
+ /* Handle the case where the open is of /proc/self/auxv or
+ /proc/<pid>/auxv, and just give it a copy of the fd for the
+ fake file we cooked up at startup (in m_main). Also, seek the
+ cloned fd back to the start. */
+ {
+ HChar name[30];
+ Char* arg1s = (Char*) ARG1;
+ SysRes sres;
+
+ VG_(sprintf)(name, "/proc/%d/auxv", VG_(getpid)());
+ if (ML_(safe_to_deref)( arg1s, 1 ) &&
+ (VG_STREQ(arg1s, name) || VG_STREQ(arg1s, "/proc/self/auxv"))
+ )
+ {
+ sres = VG_(dup)( VG_(cl_auxv_fd) );
+ SET_STATUS_from_SysRes( sres );
+ if (!sr_isError(sres)) {
+ OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
+ if (off < 0)
+ SET_STATUS_Failure( VKI_EMFILE );
+ }
+ return;
+ }
+ }
#endif // defined(VGO_linux)
/* Otherwise handle normally */
|