Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
steam-runtime-tools
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Analyze
Contributor analytics
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
steamrt
steam-runtime-tools
Commits
ea96709f
Commit
ea96709f
authored
7 years ago
by
Vivek Das Mohapatra
Browse files
Options
Downloads
Patches
Plain Diff
Comment the code thoroughly
parent
bd4b5831
No related branches found
No related tags found
1 merge request
!311
Build capsule-capture-libs from a bundled copy of libcapsule
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
capsule/capsule-dlmopen.c
+92
-17
92 additions, 17 deletions
capsule/capsule-dlmopen.c
utils/utils.c
+17
-2
17 additions, 2 deletions
utils/utils.c
with
109 additions
and
19 deletions
capsule/capsule-dlmopen.c
+
92
−
17
View file @
ea96709f
...
...
@@ -215,7 +215,8 @@ find_elf_constraints(ldlibs_t *ldlibs, struct link_map *m)
Elf
*
dso
=
NULL
;
GElf_Ehdr
ehdr
=
{
};
// absolute path or it's a "fake" link map entry which we can't use:
// absolute path or it's a "fake" link map entry which we can't use
// as there's no actual file to open and inspect:
if
(
!
m
||
!
m
->
l_name
||
(
m
->
l_name
[
0
]
!=
'/'
))
return
0
;
...
...
@@ -261,9 +262,12 @@ set_elf_constraints (ldlibs_t *ldlibs)
if
(
(
handle
=
dlopen
(
NULL
,
RTLD_LAZY
|
RTLD_NOLOAD
))
&&
(
dlinfo
(
handle
,
RTLD_DI_LINKMAP
,
&
map
)
==
0
)
)
{
// we're not guaranteed to be at the start of the link map chain:
while
(
map
->
l_prev
)
map
=
map
->
l_prev
;
// check link maps until we find one we can fill in
// our constraints from:
for
(
m
=
map
;
m
;
m
=
m
->
l_next
)
if
(
find_elf_constraints
(
ldlibs
,
m
)
)
break
;
...
...
@@ -276,10 +280,9 @@ set_elf_constraints (ldlibs_t *ldlibs)
return
(
(
ldlibs
->
elf_class
!=
ELFCLASSNONE
)
&&
(
ldlibs
->
elf_machine
|=
EM_NONE
)
);
}
// check that the currently opened
dso
at offset idx in the needed array
// check that the currently opened
DSO
at offset idx in the needed array
// matches the class & architecture of the DSO we started with:
// return true on a match, false otherwise
static
int
...
...
@@ -300,14 +303,20 @@ check_elf_constraints (ldlibs_t *ldlibs, int idx)
if
(
ldlibs
->
elf_machine
!=
ehdr
.
e_machine
)
return
0
;
// both the class (word size) and machine (architecture) match
return
1
;
}
// make sure all the string buffers are zeroed out
static
inline
void
sanitise_ldlibs
(
ldlibs_t
*
ldlibs
)
{
ldlibs
->
prefix
.
path
[
ldlibs
->
prefix
.
len
]
=
'\0'
;
}
// as we are pulling in files from a non '/' prefix ('/host' by default)
// we need to compensate for this when resolving symlinks.
// this will keep following the path at entry i in ldlibs until
// it finds something that is not a symlink.
void
resolve_symlink_prefixed
(
ldlibs_t
*
ldlibs
,
int
i
)
{
int
count
=
0
;
...
...
@@ -315,7 +324,8 @@ void resolve_symlink_prefixed (ldlibs_t *ldlibs, int i)
char
link_dir
[
PATH_MAX
];
sanitise_ldlibs
(
ldlibs
);
// prefix is unset or is /, nothing to do here:
// prefix is unset or is /, nothing to do here (we can rely on
// libc's built-in symlink following if there's no prefix):
if
(
ldlibs
->
prefix
.
len
==
0
||
(
ldlibs
->
prefix
.
path
[
0
]
==
'/'
&&
ldlibs
->
prefix
.
path
[
1
]
==
'\0'
)
)
return
;
...
...
@@ -323,8 +333,11 @@ void resolve_symlink_prefixed (ldlibs_t *ldlibs, int i)
LDLIB_DEBUG
(
ldlibs
,
DEBUG_PATH
,
"resolving (un)prefixed link in %s"
,
ldlibs
->
needed
[
i
].
path
);
// set the resolved path to the current needed path as a starting point:
safe_strncpy
(
resolved
,
ldlibs
->
needed
[
i
].
path
,
PATH_MAX
);
// now keep poking resolve_link (resolved will be updated each time)
// until it returns false:
while
(
resolve_link
(
ldlibs
->
prefix
.
path
,
resolved
,
link_dir
)
)
{
LDLIB_DEBUG
(
ldlibs
,
DEBUG_PATH
,
" resolved to: %s"
,
resolved
);
...
...
@@ -338,6 +351,7 @@ void resolve_symlink_prefixed (ldlibs_t *ldlibs, int i)
}
}
// if the path changed, copy `resolved' back into needed[].path:
if
(
count
)
safe_strncpy
(
ldlibs
->
needed
[
i
].
path
,
resolved
,
PATH_MAX
);
}
...
...
@@ -348,6 +362,15 @@ void resolve_symlink_prefixed (ldlibs_t *ldlibs, int i)
//
// will set up the needed entry at offset i correctly if we are
// successful, and clear it if we are not:
//
// designed to be called on a populated ldlib needed entry, 'name'
// is the original requested name (typically an absolute path to
// a DSO or a standard DT_NEEDED style specifier following 'libfoo.so.X')
//
// note that this expects the prefix to have already been prepended
// to the DSO path in the ldlibs->needed[i].path buffer if necessary
// this is to allow both prefixed and unprefixed DSOs to be handled
// here:
static
int
ldlib_open
(
ldlibs_t
*
ldlibs
,
const
char
*
name
,
int
i
)
{
...
...
@@ -355,6 +378,7 @@ ldlib_open (ldlibs_t *ldlibs, const char *name, int i)
LDLIB_DEBUG
(
ldlibs
,
DEBUG_SEARCH
,
"ldlib_open: target -: %s"
,
ldlibs
->
needed
[
i
].
path
);
// resolve the symlink manually if there's a prefix:
resolve_symlink_prefixed
(
ldlibs
,
i
);
LDLIB_DEBUG
(
ldlibs
,
DEBUG_SEARCH
,
...
...
@@ -380,12 +404,15 @@ ldlib_open (ldlibs_t *ldlibs, const char *name, int i)
ldlibs
->
needed
[
i
].
dso
,
acceptable
);
// either clean up the current entry so we can find a better DSO
// or (for a valid candidate) copy the original requested name in:
if
(
!
acceptable
)
clear_needed
(
&
ldlibs
->
needed
[
i
]
);
else
ldlibs
->
needed
[
i
].
name
=
strdup
(
name
);
}
// the fd will only be valid if everything worked out:
return
ldlibs
->
needed
[
i
].
fd
>=
0
;
}
...
...
@@ -432,11 +459,11 @@ iterate_ldcache (ldlibs_t *ldlibs, ldcache_entry_cb cb, void *data)
// returning a true value means we found (and set up) the DSO we wanted:
static
int
search_ldcache_cb
(
ldlibs_t
*
ldlibs
,
const
char
*
name
,
int
flag
,
unsigned
int
osv
,
uint64_t
hwcap
,
const
char
*
path
,
const
char
*
name
,
// name of the DSO in the ldcache
int
flag
,
// 1 for an ELF DSO
unsigned
int
osv
,
// OS version. we don't use this
uint64_t
hwcap
,
// HW caps. Ibid.
const
char
*
path
,
// absolute path to DSO (may be a symlink)
struct
dso_cache_search
*
target
)
{
// passed an empty query, just abort the whole search
...
...
@@ -455,9 +482,13 @@ search_ldcache_cb (ldlibs_t *ldlibs,
size_t
plen
=
ldlibs
->
prefix
.
len
;
char
*
lpath
=
ldlibs
->
needed
[
idx
].
path
;
// copy in the prefix and append the DSO path to it
safe_strncpy
(
lpath
,
prefix
,
PATH_MAX
);
safe_strncpy
(
lpath
+
plen
,
path
,
PATH_MAX
-
plen
);
// try to open the DSO. This will finish setting up the
// needed[idx] slot if successful, and reset it ready for
// another attempt if it fails:
return
ldlib_open
(
ldlibs
,
name
,
idx
);
}
...
...
@@ -532,6 +563,9 @@ search_ldpath (const char *name, const char *ldpath, ldlibs_t *ldlibs, int i)
PATH_MAX
-
plen
-
len
-
1
);
LDLIB_DEBUG
(
ldlibs
,
DEBUG_SEARCH
,
"examining %s"
,
prefix
);
// if path resolution succeeds _and_ we can open an acceptable
// DSO at that location, we're good to go (ldlib_open will
// finish setting up or clearing the needed[] entry for us):
if
(
realpath
(
prefix
,
ldlibs
->
needed
[
i
].
path
)
&&
ldlib_open
(
ldlibs
,
name
,
i
)
)
return
1
;
...
...
@@ -552,6 +586,7 @@ search_ldpath (const char *name, const char *ldpath, ldlibs_t *ldlibs, int i)
//
// Exceptions:
// we don't support DT_RPATH/DT_RUNPATH
// we don't handle ${ORIGIN} and similar
// we will respect any path prefix specified in ldlibs
//
// if a match is found, the needed array entry at i will be populated
...
...
@@ -564,13 +599,15 @@ dso_find (const char *name, ldlibs_t *ldlibs, int i)
const
char
*
ldpath
=
NULL
;
int
absolute
=
(
name
&&
(
name
[
0
]
==
'/'
));
// absolute path, or relative to CWD:
// 'name' is an absolute path, or relative to CWD:
// we may to need to do some path manipulation
if
(
strchr
(
name
,
'/'
)
)
{
size_t
plen
=
ldlibs
->
prefix
.
len
;
char
prefixed
[
PATH_MAX
];
const
char
*
target
;
// we have a path prefix, so yes, we need to do some path manipulation:
if
(
ldlibs
->
prefix
.
len
)
{
sanitise_ldlibs
(
ldlibs
);
...
...
@@ -581,7 +618,10 @@ dso_find (const char *name, ldlibs_t *ldlibs, int i)
safe_strncpy
(
prefixed
+
plen
,
name
,
PATH_MAX
-
plen
);
}
else
{
{
// name is relative... this is probably wrong?
// I don't think this can ever really happen but
// worst case is we'll simply not open a DSO whose
// path we couldn't resolve, and then move on:
safe_strncpy
(
prefixed
+
plen
,
"/"
,
PATH_MAX
-
plen
);
safe_strncpy
(
prefixed
+
plen
+
1
,
name
,
PATH_MAX
-
plen
-
1
);
}
...
...
@@ -589,18 +629,24 @@ dso_find (const char *name, ldlibs_t *ldlibs, int i)
target
=
prefixed
;
}
else
{
{
// name is a standard bare 'libfoo.so.X' spec:
target
=
name
;
}
LDLIB_DEBUG
(
ldlibs
,
DEBUG_PATH
,
"resolving path %s"
,
target
);
// this will fail for a non-absolute path, but that's OK
// if realpath lookup succeeds needed[i].path will be set correctly:
if
(
realpath
(
target
,
ldlibs
->
needed
[
i
].
path
)
)
return
ldlib_open
(
ldlibs
,
name
,
i
);
}
// path was absolute and we couldn't resolve it. give up:
if
(
absolute
)
return
0
;
// now search LD_LIBRARY_PATH, the ld.so.cache, and the default locations
// in that order (similar algorithm to the linker, but with the RPATH and
// ${ORIGIN} support dropped)
if
(
(
ldpath
=
getenv
(
"LD_LIBRARY_PATH"
))
)
if
(
(
found
=
search_ldpath
(
name
,
ldpath
,
ldlibs
,
i
))
)
return
found
;
...
...
@@ -668,6 +714,7 @@ _dso_iterate_sections (ldlibs_t *ldlibs, int idx)
GElf_Shdr
shdr
=
{};
gelf_getshdr
(
scn
,
&
shdr
);
// SHT_DYNAMIC is the only section type we care about here:
if
(
shdr
.
sh_type
==
SHT_DYNAMIC
)
{
int
i
=
0
;
...
...
@@ -676,6 +723,7 @@ _dso_iterate_sections (ldlibs_t *ldlibs, int idx)
edata
=
elf_getdata
(
scn
,
edata
);
// process eaach DT_* entry in the SHT_DYNAMIC section:
while
(
!
ldlibs
->
error
&&
gelf_getdyn
(
edata
,
i
++
,
&
dyn
)
&&
(
dyn
.
d_tag
!=
DT_NULL
)
)
...
...
@@ -683,18 +731,21 @@ _dso_iterate_sections (ldlibs_t *ldlibs, int idx)
int
skip
=
0
;
int
next
=
ldlibs
->
last_idx
;
dso_needed_t
*
needed
=
ldlibs
->
needed
;
char
*
next_dso
;
char
*
next_dso
;
// name of the dependency we're going to need
// we're only gathering DT_NEEDED (dependency) entries here:
if
(
dyn
.
d_tag
!=
DT_NEEDED
)
continue
;
next_dso
=
elf_strptr
(
needed
[
idx
].
dso
,
shdr
.
sh_link
,
dyn
.
d_un
.
d_val
);
//////////////////////////////////////////////////
// ignore the linker itself
if
(
strstr
(
next_dso
,
"ld-"
)
==
next_dso
)
continue
;
// ignore any DSOs we've been specifically told to leave out:
for
(
char
**
x
=
(
char
**
)
ldlibs
->
exclude
;
x
&&
*
x
;
x
++
)
{
if
(
strcmp
(
*
x
,
next_dso
)
==
0
)
...
...
@@ -705,11 +756,15 @@ _dso_iterate_sections (ldlibs_t *ldlibs, int idx)
break
;
}
}
if
(
skip
)
continue
;
//////////////////////////////////////////////////
// if we got this far, we have another dependency:
needed
[
idx
].
depcount
++
;
// already on our list, no need to do anything else here:
if
(
already_needed
(
needed
,
idx
,
next_dso
)
)
continue
;
...
...
@@ -728,7 +783,9 @@ _dso_iterate_sections (ldlibs_t *ldlibs, int idx)
}
else
{
// record which DSO requested the new library we found:
needed
[
next
].
requestors
[
idx
]
=
1
;
// now find the dependencies of our newest dependency:
_dso_iterate_sections
(
ldlibs
,
next
);
}
}
...
...
@@ -775,7 +832,7 @@ _dso_iterator_format_error (ldlibs_t * ldlibs)
// wrapper to format any accumulated errors and similar after
// invoking the actual dso iterator: returns true if we gathered
// all the needed info witout error, false
r
otherwise:
// all the needed info witout error, false otherwise:
static
int
dso_iterate_sections
(
ldlibs_t
*
ldlibs
,
int
idx
)
{
...
...
@@ -1094,6 +1151,8 @@ init_ldlibs (ldlibs_t *ldlibs,
if
(
errcode
)
*
errcode
=
0
;
// super important, 0 is valid but is usually stdin,
// don't want to go stomping all over that by accident:
for
(
int
x
=
0
;
x
<
DSO_LIMIT
;
x
++
)
ldlibs
->
needed
[
x
].
fd
=
-
1
;
...
...
@@ -1224,6 +1283,7 @@ dump_ld_entry (ldlibs_t *ldlibs,
return
0
;
}
// dump out the contents of the ld cache to stderr:
static
void
dump_ld_cache
(
ldlibs_t
*
ldlibs
)
{
...
...
@@ -1241,7 +1301,9 @@ wrap (const char *name,
ElfW
(
Addr
)
start
=
(
ElfW
(
Addr
))
dyn
-
base
;
// we don't know the size so we'll have to rely on the linker putting
// well formed entries into the mmap()ed DSO region.
// the utility functions expect an upper bound htough so set that to
// (tbf if the linker is putting duff entries here we're boned anyway)
//
// the utility functions expect an upper bound though so set that to
// something suitably large:
size_t
size
=
SIZE_MAX
-
base
-
(
ElfW
(
Addr
))
dyn
;
relocation_data_t
rdata
=
{
0
};
...
...
@@ -1250,6 +1312,10 @@ wrap (const char *name,
rdata
.
debug
=
debug_flags
;
rdata
.
error
=
NULL
;
rdata
.
relocs
=
wrappers
;
// if RELRO linking has happened we'll need to tweak the mprotect flags
// before monkeypatching the symbol tables, for which we will need the
// sizes, locations and current protections of any mmap()ed regions:
rdata
.
mmap_info
=
load_mmap_info
(
&
mmap_errno
,
&
mmap_error
);
if
(
mmap_errno
||
mmap_error
)
...
...
@@ -1261,17 +1327,20 @@ wrap (const char *name,
"relocation will be unable to handle RELRO linked libraries"
);
}
// make all the mmap()s writable:
for
(
int
i
=
0
;
rdata
.
mmap_info
[
i
].
start
!=
MAP_FAILED
;
i
++
)
if
(
mmap_entry_should_be_writable
(
&
rdata
.
mmap_info
[
i
]
)
)
add_mmap_protection
(
&
rdata
.
mmap_info
[
i
],
PROT_WRITE
);
process_pt_dynamic
(
(
void
*
)
start
,
// offset from phdr address to dyn section
// install any required wrappers inside the capsule:
process_pt_dynamic
(
(
void
*
)
start
,
// offset from phdr to dyn section
size
,
// fake size value (max possible value)
base
,
// address of phdr in memory
process_dt_rela
,
process_dt_rel
,
&
rdata
);
// put the mmap()/mprotect() permissions back the way they were:
for
(
int
i
=
0
;
rdata
.
mmap_info
[
i
].
start
!=
MAP_FAILED
;
i
++
)
if
(
mmap_entry_should_be_writable
(
&
rdata
.
mmap_info
[
i
]
)
)
reset_mmap_protection
(
&
rdata
.
mmap_info
[
i
]
);
...
...
@@ -1299,6 +1368,9 @@ excluded_from_wrap (const char *name, char **exclude)
// replace calls out to dlopen in the encapsulated DSO with a wrapper
// which should take care of preserving the /path-prefix and namespace
// wrapping of the original capsule_dlmopen() call.
//
// strictly speaking we can wrap things other than dlopen(),
// but that's currently all we use this for:
static
int
install_wrappers
(
void
*
dl_handle
,
capsule_item_t
*
wrappers
,
const
char
**
exclude
,
...
...
@@ -1423,7 +1495,7 @@ capsule_dlmopen (const char *dso,
}
// ==================================================================
// once we have the starting point recursively
FIND
all its DT_NEEDED
// once we have the starting point recursively
find
all its DT_NEEDED
// entries, except for the linker itself and libc, which must not
// be different between the capsule and the "real" DSO environment:
dso_iterate_sections
(
&
ldlibs
,
0
);
...
...
@@ -1488,6 +1560,7 @@ capsule_shim_dlopen(Lmid_t ns,
goto
cleanup
;
}
// find the initial DSO (ie what the caller actually asked for):
if
(
!
dso_find
(
file
,
&
ldlibs
,
0
)
)
{
int
rv
=
(
errno
==
0
)
?
EINVAL
:
errno
;
...
...
@@ -1498,6 +1571,7 @@ capsule_shim_dlopen(Lmid_t ns,
goto
cleanup
;
}
// harvest all the requested DSO's dependencies:
dso_iterate_sections
(
&
ldlibs
,
0
);
if
(
ldlibs
.
error
)
...
...
@@ -1506,6 +1580,7 @@ capsule_shim_dlopen(Lmid_t ns,
goto
cleanup
;
}
// load them up in reverse dependency order:
res
=
load_ldlibs
(
&
ldlibs
,
&
ns
,
flag
,
&
code
,
&
errors
);
if
(
!
res
)
...
...
This diff is collapsed.
Click to expand it.
utils/utils.c
+
17
−
2
View file @
ea96709f
...
...
@@ -24,6 +24,9 @@
unsigned
long
debug_flags
;
// like strncpy except it guarantees the final byte is NUL in
// case we truncated the string. does not yet warn you in any
// way about truncation though, should probably fix that:
char
*
safe_strncpy
(
char
*
dest
,
const
char
*
src
,
size_t
n
)
{
char
*
rv
=
strncpy
(
dest
,
src
,
n
);
...
...
@@ -31,6 +34,16 @@ char *safe_strncpy (char *dest, const char *src, size_t n)
return
rv
;
}
// prefix is the root of the external tree we're patching in
// with libcapsule, path is what we're trying to resolve if
// it is a symlink. dir is a scratch space we're going to use.
// all three must have at least PATH_MAX chars allocated.
//
// Designed to be called repeatedly, starting with an ABSOLUTE
// path the first time. Will write the resolved link back into
// path each time and return true, until fed a path which is
// not a symlink, at which point it will leave path alone and
// return false:
int
resolve_link
(
const
char
*
prefix
,
char
*
path
,
char
*
dir
)
{
int
dfd
;
...
...
@@ -44,8 +57,10 @@ int resolve_link(const char *prefix, char *path, char *dir)
if
(
end
)
*
end
=
'\0'
;
else
strcpy
(
dir
,
"."
);
strcpy
(
dir
,
"."
);
// not sure this is right, FIXME?
// but as long as the first call to us
// in any sequence was an absolute path
// this will never come up
dfd
=
open
(
dir
,
O_RDONLY
);
if
(
dfd
<
0
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment