In the dynamic library build, Noise_XK_* functions and some private functions (dump, fail, debug, etc.) leaked into the so file's dynamic symbol exports.
readelf -W --dyn-syms /path/to/liboprf-0.4.0/lib/liboprf.so.0
readelf output
[NOTE: UND symbols are omitted]
58: 0000000000006010 139 FUNC GLOBAL DEFAULT 14 toprf_Evaluate
59: 0000000000011960 11 FUNC GLOBAL DEFAULT 14 Noise_XK_rcode_is_success
60: 0000000000011830 135 FUNC GLOBAL DEFAULT 14 Noise_XK_unpack_message_with_auth_level
61: 0000000000013b20 166 FUNC GLOBAL DEFAULT 14 Noise_XK_session_get_status
62: 0000000000004d60 9 FUNC GLOBAL DEFAULT 14 oprf_KeyGen
63: 000000000000d760 96 FUNC GLOBAL DEFAULT 14 Noise_XK_decrypt_and_hash
64: 000000000001a018 8 OBJECT GLOBAL DEFAULT 24 log_file
65: 0000000000013160 460 FUNC GLOBAL DEFAULT 14 Noise_XK_session_free
66: 0000000000005a90 296 FUNC GLOBAL DEFAULT 14 coeff
67: 000000000000d7c0 224 FUNC GLOBAL DEFAULT 14 Noise_XK_mix_dh
68: 0000000000012230 296 FUNC GLOBAL DEFAULT 14 Noise_XK_serialize_peer_secret
69: 0000000000012790 25 FUNC GLOBAL DEFAULT 14 Noise_XK_device_get_static_pub
70: 00000000000080a0 816 FUNC GLOBAL DEFAULT 14 tpdkg_start_tp
71: 0000000000007c40 307 FUNC GLOBAL DEFAULT 14 tpdkg_peer_input_size
72: 00000000000126b0 123 FUNC GLOBAL DEFAULT 14 Noise_XK_device_get_info
73: 00000000000127b0 7 FUNC GLOBAL DEFAULT 14 Noise_XK_peer_get_id
74: 0000000000007f60 13 FUNC GLOBAL DEFAULT 14 tpdkg_peer_not_done
75: 0000000000012750 8 FUNC GLOBAL DEFAULT 14 Noise_XK_device_get_peers_counter
76: 0000000000012d70 1003 FUNC GLOBAL DEFAULT 14 Noise_XK_session_create_responder
77: 00000000000118e0 118 FUNC GLOBAL DEFAULT 14 Noise_XK_unsafe_unpack_message
78: 00000000000060a0 237 FUNC GLOBAL DEFAULT 14 toprf_thresholdcombine
79: 00000000000127c0 131 FUNC GLOBAL DEFAULT 14 Noise_XK_peer_get_info
80: 0000000000004d70 285 FUNC GLOBAL DEFAULT 14 oprf_Finalize
81: 0000000000011990 440 FUNC GLOBAL DEFAULT 14 Noise_XK_device_create
82: 0000000000007ec0 129 FUNC GLOBAL DEFAULT 14 tpdkg_peer_set_bufs
83: 00000000000062f0 668 FUNC GLOBAL DEFAULT 14 dkg_start
84: 0000000000014070 1150 FUNC GLOBAL DEFAULT 14 Noise_XK__session_create_initiator_with_ephemeral
85: 000000000000cbc0 160 FUNC GLOBAL DEFAULT 14 tpdkg_recv_err
86: 0000000000011630 12 FUNC GLOBAL DEFAULT 14 Noise_XK_uu___is_Stuck
87: 0000000000011970 12 FUNC GLOBAL DEFAULT 14 Noise_XK_rcode_is_error
88: 0000000000012620 43 FUNC GLOBAL DEFAULT 14 Noise_XK_device_lookup_peer_by_id
89: 000000000000d170 22 FUNC GLOBAL DEFAULT 14 Noise_XK_hash
90: 0000000000007ff0 166 FUNC GLOBAL DEFAULT 14 tpdkg_tp_set_bufs
91: 0000000000012650 85 FUNC GLOBAL DEFAULT 14 Noise_XK_device_lookup_peer_by_static
92: 000000000000d010 8 FUNC GLOBAL DEFAULT 14 Noise_XK_bytes_to_nonce
93: 00000000000116f0 12 FUNC GLOBAL DEFAULT 14 Noise_XK_uu___is_Conf_level
94: 0000000000011b50 568 FUNC GLOBAL DEFAULT 14 Noise_XK_device_create_from_secret
95: 0000000000006590 503 FUNC GLOBAL DEFAULT 14 dkg_verify_commitment
96: 000000000000d060 122 FUNC GLOBAL DEFAULT 14 Noise_XK_aead_encrypt
97: 0000000000007f70 117 FUNC GLOBAL DEFAULT 14 tpdkg_peer_free
98: 0000000000012740 12 FUNC GLOBAL DEFAULT 14 Noise_XK_device_sessions_counter_is_saturated
99: 0000000000006790 268 FUNC GLOBAL DEFAULT 14 dkg_verify_commitments
100: 0000000000005760 173 FUNC GLOBAL DEFAULT 14 oprf_Blind
101: 0000000000013c90 73 FUNC GLOBAL DEFAULT 14 Noise_XK_session_get_id
102: 0000000000012140 240 FUNC GLOBAL DEFAULT 14 Noise_XK_device_remove_peer
103: 0000000000011750 12 FUNC GLOBAL DEFAULT 14 Noise_XK_uu___is_No_level
104: 0000000000006ab0 326 FUNC GLOBAL DEFAULT 14 dump
105: 0000000000011f50 487 FUNC GLOBAL DEFAULT 14 Noise_XK_device_add_peer
106: 0000000000012770 25 FUNC GLOBAL DEFAULT 14 Noise_XK_device_get_static_priv
107: 0000000000011700 76 FUNC GLOBAL DEFAULT 14 Noise_XK___proj__Conf_level__item__l
108: 000000000000d040 25 FUNC GLOBAL DEFAULT 14 Noise_XK_dh
109: 0000000000006c00 271 FUNC GLOBAL DEFAULT 14 fail
110: 0000000000011780 31 FUNC GLOBAL DEFAULT 14 Noise_XK_encap_message_p_free
111: 0000000000006190 345 FUNC GLOBAL DEFAULT 14 toprf_3hashtdh
112: 0000000000013330 838 FUNC GLOBAL DEFAULT 14 Noise_XK_session_write
113: 0000000000011810 19 FUNC GLOBAL DEFAULT 14 Noise_XK_pack_message
114: 000000000000cc60 879 FUNC GLOBAL DEFAULT 14 tpdkg_cheater_msg
115: 000000000000d630 220 FUNC GLOBAL DEFAULT 14 Noise_XK_mix_psk
116: 0000000000013a40 222 FUNC GLOBAL DEFAULT 14 Noise_XK_session_compute_next_message_len
117: 0000000000012730 8 FUNC GLOBAL DEFAULT 14 Noise_XK_device_get_sessions_counter
118: 0000000000004e90 1968 FUNC GLOBAL DEFAULT 14 expand_message_xmd
119: 0000000000007a30 523 FUNC GLOBAL DEFAULT 14 tpdkg_tp_peer_msg
120: 0000000000013bd0 185 FUNC GLOBAL DEFAULT 14 Noise_XK_session_get_hash
121: 0000000000011770 11 FUNC GLOBAL DEFAULT 14 Noise_XK_encap_message_p_is_null
122: 0000000000006960 336 FUNC GLOBAL DEFAULT 14 dkg_reconstruct
123: 0000000000012850 25 FUNC GLOBAL DEFAULT 14 Noise_XK_peer_get_static
124: 0000000000013680 955 FUNC GLOBAL DEFAULT 14 Noise_XK_session_read
125: 000000000000cfd0 54 FUNC GLOBAL DEFAULT 14 Noise_XK_lbytes_eq
126: 0000000000011640 76 FUNC GLOBAL DEFAULT 14 Noise_XK___proj__Stuck__item___0
127: 0000000000013ce0 304 FUNC GLOBAL DEFAULT 14 Noise_XK_session_get_info
128: 0000000000007f50 13 FUNC GLOBAL DEFAULT 14 tpdkg_tp_not_done
129: 000000000000d190 155 FUNC GLOBAL DEFAULT 14 Noise_XK_mix_hash
130: 0000000000013fc0 164 FUNC GLOBAL DEFAULT 14 Noise_XK_session_reached_max_security
131: 0000000000011980 12 FUNC GLOBAL DEFAULT 14 Noise_XK_rcode_is_stuck
132: 000000000000d0e0 132 FUNC GLOBAL DEFAULT 14 Noise_XK_aead_decrypt
133: 0000000000005830 186 FUNC GLOBAL DEFAULT 14 oprf_Unblind
134: 000000000001a014 4 OBJECT GLOBAL DEFAULT 24 debug
135: 00000000000083d0 594 FUNC GLOBAL DEFAULT 14 tpdkg_start_peer
136: 0000000000005810 21 FUNC GLOBAL DEFAULT 14 oprf_Evaluate
137: 0000000000011e80 197 FUNC GLOBAL DEFAULT 14 Noise_XK_serialize_device_secret
138: 0000000000012870 1278 FUNC GLOBAL DEFAULT 14 Noise_XK_session_create_initiator
139: 00000000000117a0 102 FUNC GLOBAL DEFAULT 14 Noise_XK_pack_message_with_conf_level
140: 0000000000012360 689 FUNC GLOBAL DEFAULT 14 Noise_XK_deserialize_peer_secret
141: 0000000000007510 706 FUNC GLOBAL DEFAULT 14 tpdkg_tp_input_sizes
142: 0000000000005e10 508 FUNC GLOBAL DEFAULT 14 toprf_thresholdmult
143: 000000000000d710 69 FUNC GLOBAL DEFAULT 14 Noise_XK_encrypt_and_hash
144: 0000000000011d90 232 FUNC GLOBAL DEFAULT 14 Noise_XK_device_free
145: 0000000000007d80 314 FUNC GLOBAL DEFAULT 14 tpdkg_peer_output_size
146: 0000000000012760 12 FUNC GLOBAL DEFAULT 14 Noise_XK_device_peers_counter_is_saturated
147: 0000000000005bc0 583 FUNC GLOBAL DEFAULT 14 toprf_create_shares
148: 00000000000115e0 76 FUNC GLOBAL DEFAULT 14 Noise_XK___proj__Error__item___0
149: 000000000000d470 442 FUNC GLOBAL DEFAULT 14 Noise_XK_kdf
150: 0000000000013e10 76 FUNC GLOBAL DEFAULT 14 Noise_XK_session_get_peer_id
151: 0000000000011760 8 FUNC GLOBAL DEFAULT 14 Noise_XK___proj__Mkencap_message_p_or_null__item__emp
152: 0000000000011690 11 FUNC GLOBAL DEFAULT 14 Noise_XK_uu___is_Auth_level
153: 00000000000115c0 11 FUNC GLOBAL DEFAULT 14 Noise_XK_uu___is_Success
154: 00000000000116a0 75 FUNC GLOBAL DEFAULT 14 Noise_XK___proj__Auth_level__item__l
155: 000000000000d230 567 FUNC GLOBAL DEFAULT 14 Noise_XK_hmac
156: 0000000000005640 282 FUNC GLOBAL DEFAULT 14 voprf_hash_to_group
157: 00000000000144f0 886 FUNC GLOBAL DEFAULT 14 Noise_XK__session_create_responder_with_ephemeral
158: 000000000001a008 4 OBJECT GLOBAL DEFAULT 23 Noise_XK_num_pattern_messages
159: 000000000000d020 20 FUNC GLOBAL DEFAULT 14 Noise_XK_dh_secret_to_public
160: 00000000000118c0 17 FUNC GLOBAL DEFAULT 14 Noise_XK_unpack_message
161: 00000000000078d0 352 FUNC GLOBAL DEFAULT 14 tpdkg_tp_output_size
162: 00000000000115d0 12 FUNC GLOBAL DEFAULT 14 Noise_XK_uu___is_Error
163: 0000000000013e60 345 FUNC GLOBAL DEFAULT 14 Noise_XK_session_get_peer_info
164: 000000000000a9b0 8708 FUNC GLOBAL DEFAULT 14 tpdkg_peer_next
165: 00000000000068a0 183 FUNC GLOBAL DEFAULT 14 dkg_finish
166: 00000000000077e0 233 FUNC GLOBAL DEFAULT 14 tpdkg_tp_input_size
167: 0000000000008630 9078 FUNC GLOBAL DEFAULT 14 tpdkg_tp_next
Possible fix:
- Add
__attribute__((visibility("default"))) at the end of public function declarations.
- Compile with
-fvisibility=hidden which hides all symbols without a visibility attribute.
Ideally I would recommend visibility("protected") over visibility("default"). The blocker is GNU ld doesn't like visibility("protected") inside public header files. When a client passes visibility("protected") to a function declaration, ld (linktime) will look up the function's symbol name across all translation units (the .o files) but it will not look at dynamic libraries. (This means your clients cannot link against your libraries due to mis-used visibility attributes.) You can split the headers into a public version and a dev version (like what I did for my test project), although that would be a huge fix.
Backgrounder:
On Linux, every symbol in a dylib is publicly exported by default. This is a design decision of the GCC toolchain from the 90s.
As another decision decision, ld.so (the runtime loader) does not maintain a graph data structure for your dylib's dependencies. Instead it serializes the graph into an array and uses that same array for every symbol resolve.
This combined linker-loader behavior does not make sense in the age of the internet as people pull a dozen of libraries for every project. An over-exported symbol table increases the risk of symbol clashing. See also this old PHP bug.
P.S. I suggest using this to trace ld.so's resolution order:
LD_DEBUG=reloc:symbols:bindings ./build/test_library 1>&2 2>/tmp/ld-debug.txt
In the dynamic library build,
Noise_XK_*functions and some private functions (dump, fail, debug, etc.) leaked into thesofile's dynamic symbol exports.readelf output
Possible fix:
__attribute__((visibility("default")))at the end of public function declarations.-fvisibility=hiddenwhich hides all symbols without a visibility attribute.Ideally I would recommend
visibility("protected")overvisibility("default"). The blocker is GNU ld doesn't likevisibility("protected")inside public header files. When a client passesvisibility("protected")to a function declaration, ld (linktime) will look up the function's symbol name across all translation units (the.ofiles) but it will not look at dynamic libraries. (This means your clients cannot link against your libraries due to mis-used visibility attributes.) You can split the headers into a public version and a dev version (like what I did for my test project), although that would be a huge fix.Backgrounder:
On Linux, every symbol in a dylib is publicly exported by default. This is a design decision of the GCC toolchain from the 90s.
As another decision decision, ld.so (the runtime loader) does not maintain a graph data structure for your dylib's dependencies. Instead it serializes the graph into an array and uses that same array for every symbol resolve.
This combined linker-loader behavior does not make sense in the age of the internet as people pull a dozen of libraries for every project. An over-exported symbol table increases the risk of symbol clashing. See also this old PHP bug.
P.S. I suggest using this to trace ld.so's resolution order: