Skip to content

Commit 6109106

Browse files
committed
Expand the list of got_audit expected duplicate symbols.
1 parent 694924f commit 6109106

File tree

1 file changed

+91
-10
lines changed

1 file changed

+91
-10
lines changed

scripts/got_audit.py

Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import collections
1414
import pathlib
15-
from typing import TYPE_CHECKING, Dict, List, Tuple
15+
from typing import TYPE_CHECKING
1616

1717
import gdb
1818

@@ -27,9 +27,82 @@ class GotAuditCommand(GotCommand, GenericCommand):
2727
_cmdline_ = "got-audit"
2828
_syntax_ = f"{_cmdline_} [FUNCTION_NAME ...] "
2929
_example_ = "got-audit read printf exit"
30-
_symbols_: Dict[str, List[str]] = collections.defaultdict(list)
31-
_paths_: Dict[str, List[str]] = collections.defaultdict(list)
32-
_expected_dups_ = ['__cxa_finalize']
30+
_symbols_: dict[str, list[str]] = collections.defaultdict(list)
31+
_paths_: dict[str, list[str]] = collections.defaultdict(list)
32+
33+
_expected_dups_ = [
34+
"__cxa_finalize",
35+
36+
# Symbols that appear in both GNU's libc.so and libm.so
37+
"copysign", "copysignf", "copysignl", "__finite", "finite",
38+
"__finitef", "finitef", "__finitel", "finitel", "frexp",
39+
"frexpf", "frexpl", "ldexp", "ldexpf", "ldexpl", "modf",
40+
"modff", "modfl", "scalbn", "scalbnf", "scalbnl", "__signbit",
41+
"__signbitf", "__signbitl",
42+
43+
# Symbols that appear in both GNU's libc.so and libattr.so
44+
"fgetxattr", "flistxattr", "fremovexattr", "fsetxattr",
45+
"getxattr", "lgetxattr", "listxattr", "llistxattr",
46+
"lremovexattr", "lsetxattr", "removexattr", "setxattr",
47+
48+
# Symbols that appear in both GNU's libc.so and libtirpc.so
49+
"authdes_create", "authdes_pk_create", "_authenticate",
50+
"authnone_create", "authunix_create",
51+
"authunix_create_default", "bindresvport", "callrpc",
52+
"clnt_broadcast", "clnt_create", "clnt_pcreateerror",
53+
"clnt_perrno", "clnt_perror", "clntraw_create",
54+
"clnt_spcreateerror", "clnt_sperrno", "clnt_sperror",
55+
"clnttcp_create", "clntudp_bufcreate", "clntudp_create",
56+
"clntunix_create", "get_myaddress", "getnetname",
57+
"getpublickey", "getrpcport", "host2netname",
58+
"key_decryptsession", "key_decryptsession_pk",
59+
"key_encryptsession", "key_encryptsession_pk", "key_gendes",
60+
"key_get_conv", "key_secretkey_is_set", "key_setnet",
61+
"key_setsecret", "__libc_clntudp_bufcreate", "netname2host",
62+
"netname2user", "pmap_getmaps", "pmap_getport",
63+
"pmap_rmtcall", "pmap_set", "pmap_unset", "registerrpc",
64+
"_rpc_dtablesize", "rtime", "_seterr_reply", "svcerr_auth",
65+
"svcerr_decode", "svcerr_noproc", "svcerr_noprog",
66+
"svcerr_progvers", "svcerr_systemerr", "svcerr_weakauth",
67+
"svc_exit", "svcfd_create", "svc_getreq", "svc_getreq_common",
68+
"svc_getreq_poll", "svc_getreqset", "svcraw_create",
69+
"svc_register", "svc_run", "svc_sendreply", "svctcp_create",
70+
"svcudp_bufcreate", "svcudp_create", "svcunix_create",
71+
"svcunixfd_create", "svc_unregister", "user2netname",
72+
"xdr_accepted_reply", "xdr_array", "xdr_authunix_parms",
73+
"xdr_bool", "xdr_bytes", "xdr_callhdr", "xdr_callmsg",
74+
"xdr_char", "xdr_cryptkeyarg", "xdr_cryptkeyarg2",
75+
"xdr_cryptkeyres", "xdr_des_block", "xdr_double", "xdr_enum",
76+
"xdr_float", "xdr_free", "xdr_getcredres", "xdr_hyper",
77+
"xdr_int", "xdr_int16_t", "xdr_int32_t", "xdr_int64_t",
78+
"xdr_int8_t", "xdr_keybuf", "xdr_key_netstarg",
79+
"xdr_key_netstres", "xdr_keystatus", "xdr_long",
80+
"xdr_longlong_t", "xdrmem_create", "xdr_netnamestr",
81+
"xdr_netobj", "xdr_opaque", "xdr_opaque_auth", "xdr_pmap",
82+
"xdr_pmaplist", "xdr_pointer", "xdr_quad_t", "xdrrec_create",
83+
"xdrrec_endofrecord", "xdrrec_eof", "xdrrec_skiprecord",
84+
"xdr_reference", "xdr_rejected_reply", "xdr_replymsg",
85+
"xdr_rmtcall_args", "xdr_rmtcallres", "xdr_short",
86+
"xdr_sizeof", "xdrstdio_create", "xdr_string", "xdr_u_char",
87+
"xdr_u_hyper", "xdr_u_int", "xdr_uint16_t", "xdr_uint32_t",
88+
"xdr_uint64_t", "xdr_uint8_t", "xdr_u_long",
89+
"xdr_u_longlong_t", "xdr_union", "xdr_unixcred",
90+
"xdr_u_quad_t", "xdr_u_short", "xdr_vector", "xdr_void",
91+
"xdr_wrapstring", "xprt_register", "xprt_unregister",
92+
93+
# Symbols that appear in libsasl2 and in its related libs
94+
"_plug_buf_alloc", "_plug_challenge_prompt", "_plug_decode",
95+
"_plug_decode_free", "_plug_decode_init", "_plug_find_prompt",
96+
"_plug_free_secret", "_plug_free_string",
97+
"_plug_get_error_message", "_plug_get_password",
98+
"_plug_get_realm", "_plug_get_simple", "_plug_iovec_to_buf",
99+
"_plug_ipfromstring", "_plug_make_fulluser",
100+
"_plug_make_prompts", "_plug_parseuser",
101+
"_plug_snprintf_os_info", "_plug_strdup",
102+
103+
# Symbols that appear in libresolv and libvncserver
104+
"__b64_ntop", "__b64_pton",
105+
]
33106

34107
def get_symbols_from_path(self, elf_file):
35108
nm = gef.session.constants["nm"]
@@ -39,15 +112,15 @@ def get_symbols_from_path(self, elf_file):
39112
words = line.split()
40113
# Record the symbol if it is in the text section or
41114
# an indirect function or weak symbol
42-
if len(words) == 3 and words[-2] in ('T', 'i', 'I', 'v', 'V', 'w', 'W'):
43-
sym = words[-1].split('@')[0]
115+
if len(words) == 3 and words[-2] in ("T", "i", "I", "v", "V", "w", "W"):
116+
sym = words[-1].split("@")[0]
44117
if elf_file not in self._symbols_[sym]:
45118
self._symbols_[sym].append(elf_file)
46119
self._paths_[elf_file].append(sym)
47120

48121
@only_if_gdb_running
49-
def do_invoke(self, argv: List[str]) -> None:
50-
# Build a list of the symbols provided by each path, and
122+
def do_invoke(self, argv: list[str]) -> None:
123+
# Build a list of the symbols provided by each library path, and
51124
# a list of paths that provide each symbol.
52125
for section in gef.memory.maps:
53126
if (section.path not in self._paths_
@@ -56,19 +129,27 @@ def do_invoke(self, argv: List[str]) -> None:
56129
self.get_symbols_from_path(section.path)
57130
return super().do_invoke(argv)
58131

59-
def build_line(self, name: str, color: str, address_val: int, got_address: int) -> str:
132+
def build_line(self, name: str, path: str, color: str, address_val: int, got_address: int) -> str:
60133
line = Color.colorify(f"{name}", color)
61134
found = 0
62135
for section in gef.memory.maps:
63136
if not section.contains(got_address):
64137
continue
65138
line += f" : {section.path}"
66139
found = 1
67-
short_name = name.split('@')[0]
140+
short_name = name.split("@")[0]
141+
# Symbol duplication isn't a strong signal for namespace tampering, but it should not be
142+
# allowed without review. Developers should register the symbols that multiple libraries
143+
# export. (Though the current implementation of hard-coding them in this tool should be
144+
# replaced with a more flexible approach.)
68145
if (len(self._symbols_[short_name]) > 1
69146
and short_name not in self._expected_dups_):
70147
line += f" :: ERROR {short_name} found in multiple paths ({str(self._symbols_[short_name])})"
148+
# Symbols within a Section are allowed to resolve to an address within the same Section.
149+
# This is usually an unresolved symbol. In any case, we aren't concerned that a library
150+
# will subvert its own functionality through namespace tampering.
71151
if (section.path != "[vdso]"
152+
and section.path != path
72153
and short_name not in self._paths_[section.path]):
73154
line += f" :: ERROR {short_name} not exported by {section.path}"
74155
break

0 commit comments

Comments
 (0)