Regression: NULL l_addr in link_map structure for vdso on 5.5.0

Open
#3,066 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
32/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
c, cpp, linux

Research direction

Start with the minimal vdsoaddr application and reproduce it under rr, comparing the link_map l_addr value with and without rr. Read elf/setup-vdso.h, especially setup_vdso(), and inspect the librrpage.so PT_LOAD entries and commit 4be0255d. Done means the vdso link_map l_addr remains valid under rr without regressing normal execution.

Written by the indexing model from the issue text.

Description

I've discovered a regression from 5.4.0 to 5.5.0. Applications that use dlopen() to obtain a dynamic linker struct link_map pointer corresponding to the vdso and observe the l_addr field will find it to be NULL. Here's a minimal application that crashes on 5.5.0 (link with -ldl):

#include <assert.h>
#include <link.h>
#include <string.h>

int main(void) {
	const struct link_map *l = dlopen(NULL, RTLD_LAZY);
	while(l && strcmp(l->l_name, "linux-vdso.so.1"))
		l = l->l_next;
	assert(l->l_addr);

	return 0;
}

It looks like the NULL originates in ld-linux.so's setup_vdso() function. When running without rr, all of the PT_LOAD entries in the program header have a p_vaddr of 0, so line 52 has no effect and line 64 is equivalent to l->l_addr = l->l_map_start. Under rr, the first PT_LOAD entry has a p_vaddr that matches l->l_map_start, so line 64 instead resets l->l_addr to NULL.

It looks like for setup_vdso() to work correctly on librrpage.so, all of its PT_LOAD entries would have to have a p_vaddr of 0, which is infeasible. And since setup_vdso() is an inline function, it cannot be interposed. Perhaps rr can just manually set the l_addr field after the dynamic linker is finished?

I'm using glibc 2.33 from Debian:

$ apt policy libc6
libc6:
  Installed: 2.33-1

It looks like this was introduced in 4be0255d, which proxies the vdso. Here's my bisection script:

#!/bin/sh

mydir="`dirname "$0"`"
set -ev
[ -e vdsoaddr ] || c99 -o vdsoaddr "$mydir/vdsoaddr.c" -ldl
[ -e vdsoaddr-0 ] && rm -rf vdsoaddr-0
git cherry HEAD dbc94c6f | grep ^+ >/dev/null && git cherry-pick -n dbc94c6f
./configure
make -j8
git reset --hard
_RR_TRACE_DIR="." bin/rr ./vdsoaddr || false
Dominant language
C++
Stars
10.7k
Forks
662
Avg merge
2d 3h
Merged PRs (30d)
2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rr-debugger/rr

All issues in rr-debugger/rr

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.