1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
|
<part id='qa'>
<title>Quality Assurance</title>
<chapter id='qa-notices'>
<title>QA Notices</title>
<para>
Here we'll go over each QA notice and what you (as a developer) can do to fix
the issue. If you're a user, you should of course go
<ulink url="https://bugs.gentoo.org/">file a bug</ulink>. We'll only cover the
non-obvious notices here.
</para>
<para>
In pretty much all cases, you should try and get these issues resolved
upstream rather than simply fixing them in our ebuilds.
</para>
<sect1 id='qa-scanelf-runpath'>
<title>Scanelf: Insecure RUNPATHs</title>
<para>
<programlisting>
QA Notice: The following files contain insecure RUNPATHs
</programlisting>
</para>
<para>
Some of the ELFs that would be installed on the system have insecure dynamic
RUNPATH tags. RUNPATH tags are a hardcoded list of filesystem paths that
will be searched at runtime when the ELF is executed. If the ELF has a
world accessible directory hardcoded in it, then a malicious person can
inject code at runtime by adding their own libraries to the directory.
</para>
<para>
Here are some of the common problems and their solutions.
<itemizedlist>
<listitem>
<para>Libtool - old versions of libtool would use too many -rpath flags</para>
<para>Solution: Regenerate the autotool code</para>
</listitem>
<listitem>
<para>Perl - some versions of perl would use incorrect -rpath flags</para>
<para>Solution: Upgrade system perl build modules</para>
</listitem>
<listitem>
<para>Crappy build system - the custom build system uses -rpath incorrectly</para>
<para>Solution: Review the LDFLAGS in the build system and make them not suck</para>
</listitem>
<listitem>
<para>Crappy ebuild - the ebuild installs ELFs instead of using the package's build system</para>
<para>Solution: Fix the crappy ebuild to use the package's build system</para>
</listitem>
</itemizedlist>
</para>
</sect1>
<sect1 id='qa-scanelf-textrel'>
<title>Scanelf: Runtime Text Relocations (TEXTRELS)</title>
<para>
<programlisting>
QA Notice: The following files contain runtime text relocations
</programlisting>
</para>
<para>
Please see the Gentoo Hardened <ulink url="https://wiki.gentoo.org/wiki/Hardened/Textrels_Guide">PIC Fix Guide</ulink>.
</para>
</sect1>
<sect1 id='qa-scanelf-execstack'>
<title>Scanelf: Executable Stack (EXECSTACK)</title>
<para>
<programlisting>
QA Notice: The following files contain executable stacks
</programlisting>
</para>
<para>
Please see the Gentoo Hardened <ulink url="https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart">GNU Stack Guide</ulink>.
</para>
</sect1>
<sect1 id='qa-scanelf-soname'>
<title>Scanelf: Missing Shared Object Name (SONAME)</title>
<para>
<programlisting>
QA Notice: The following shared libraries lack a SONAME
</programlisting>
</para>
<para>
A shared library that you would link against lacks an ELF SONAME tag. With
simpler libraries, this can be acceptable, but with any sort of ABI sane
setup, you need the SONAME tag. This tag is how the system linker tells the
loader what libraries a program needs at runtime. With a missing SONAME,
the linker needs to guess and with many cases, this guess will not work for
long.
</para>
<para>
To fix this issue, make sure the shared library is linked with the proper
<option>-Wl,-soname,...</option> flag. You will need to replace the
<replaceable>...</replaceable> part with the actual ABI name. For example,
if the library is named <filename>libfoo.so.1.2.3</filename>, you will
probably want to specify <option>-Wl,-soname,libfoo.so.1</option>.
</para>
<para>
Note that this warning only applies to shared libraries that you would link
against. It certainly does not apply to plugins that you would dynamically
load. However, plugins should not exist in the main library directory, but
rather an application specific subdirectory in the library directory. In
other words, it should be <filename>/usr/lib/app/plugin.so</filename> rather
than <filename>/usr/lib/plugin.so</filename>.
</para>
</sect1>
<sect1 id='qa-scanelf-needed'>
<title>Scanelf: Missing Needed Entries</title>
<para>
<programlisting>
QA Notice: The following shared libraries lack NEEDED entries
</programlisting>
</para>
<para>
This warning comes up when a library does not actually seem to need any
other libraries in order to run. Rarely is this true as almost every
library will need at least the system C library.
</para>
<para>
Once you've determined that the library is indeed being generated
incorrectly, you will need to dig into the build system to make sure that
it pulls in the libraries it needs. Often times, this is because the
build system invokes the system linker (<command>ld</command>) directly
instead of the system compiler driver (<command>gcc</command>).
</para>
</sect1>
<sect1 id='qa-unresolved-soname-dependencies'>
<title>Unresolved soname dependencies</title>
<para>
<programlisting>
QA Notice: Unresolved soname dependencies
</programlisting>
</para>
<para>
This warning comes up when a library or executable has one or more
soname dependencies (found in its NEEDED.ELF.2 metadata) that could
not be resolved by usual means. If you run <command>ldd</command> on
files like these then it will report a "not found" error for each
unresolved soname dependency. In order to correct problems with
soname dependency resolution, use one or more of the approaches
described in the following sections.
</para>
<para>
Content of the NEEDED.ELF.2 metadata file may be useful for
debugging purposes. Find the NEEDED.ELF.2 file in the
${D}/../build-info/ directory after the ebuild src_install phase
completes, or in the /var/db/pkg/*/*/ directory for an installed
package. Each line of the NEEDED.ELF.2 file contains semicolon
separated values for a single ELF file. The soname dependencies are
found in the DT_NEEDED column:
<programlisting>
E_MACHINE;path;DT_SONAME;DT_RUNPATH;DT_NEEDED;multilib category
</programlisting>
</para>
<sect2 id='qa-unresolved-soname-dependencies-resolved-bu-external-dependencies'>
<title>External dependencies</title>
<para>
For packages that install pre-built binaries, it may be possible to
resolve soname dependencies simply by adding dependencies for one
or more other packages that are known to provide the needed sonames.
</para>
</sect2>
<sect2 id='qa-unresolved-soname-dependencies-resolved-by-removal-of-unecessary-files'>
<title>Removal of unecessary files</title>
<para>
For packages that install pre-built binaries, it may be possible to
resolve soname dependencies simply by removing unnecessary files
which have unresolved soname dependencies. For example, some pre-built
binary packages include binaries intended for irrelevant architectures
or operating systems, and these files can simply be removed because
they are unnecessary.
</para>
</sect2>
<sect2 id='qa-unresolved-soname-dependencies-resolved-by-addition-of-dt-runpath-entries'>
<title>Addition of DT_RUNPATH entries</title>
<para>
If the relevant dependencies are installed in a location that is not
included in the dynamic linker search path, then it's necessary for
files to include a DT_RUNPATH entry which refers to the appropriate
directory. The special $ORIGIN value can be used to create a relative
path reference in DT_RUNPATH, where $ORIGIN is a placeholder for the
directory where the file having the DT_RUNPATH entry is located.
</para>
<para>
For pre-built binaries, it may be necessary to fix up DT_RUNPATH using
<command>patchelf --set-rpath</command>. For example, use
<command>patchelf --set-rpath '$ORIGIN'</command> if a given binary
should link to libraries found in the same directory as the binary
itself, or use <command>patchelf --set-rpath '$ORIGIN/libs'</command>
if a given binary should link to libraries found in a subdirectory
named libs found in the same directory as the binary itself.
</para>
<para>
For binaries built from source, a flag like
<option>-Wl,-rpath,/path/of/directory/containing/libs</option> will
create binaries with the desired DT_RUNPATH entry.
</para>
</sect2>
<sect2 id='qa-unresolved-soname-dependencies-resolved-by-addition-of-dt-soname-settings'>
<title>Addition of DT_SONAME settings</title>
<para>
If a package installs dynamic libraries which do not set DT_SONAME,
then this can lead to unresolved soname dependencies.
For dynamic libraries built from source, a flag like
<option>-Wl,-soname=foo.so.1</option> will create a DT_SONAME setting.
For pre-built dynamic libraries, it may be necessary to fix up
DT_SONAME using <command>patchelf --set-soname</command>.
</para>
</sect2>
<sect2 id='qa-unresolved-soname-dependencies-resolved-by-adjustment-to-portage-soname-resolution-logic'>
<title>Adjustment to Portage soname resolution logic</title>
<para>
It may be necessary to adjust Portage soname resolution logic in
order to account for special circumstances. For example, Portage
soname resolution tolerates missing DT_SONAME for dynamic libraries
that a package installs in a directory that its binaries reference
via DT_RUNPATH. This behavior is useful for packages that have
internal dynamic libraries stored in a private directory. An example
is ebtables, as discussed in
<ulink url="https://bugs.gentoo.org/646190">bug 646190</ulink>.
</para>
</sect2>
</sect1>
<sect1 id='qa-abs-lib-link'>
<title>Absolute Symlink In Library Directory</title>
<para>
<programlisting>
QA Notice: Found an absolute symlink in a library directory
</programlisting>
</para>
<para>
If you want to use symlinks in library directories, please use either a
relative symlink or a linker script. This can cause problems when working
with cross-compiler systems or when accessing systems in a different ROOT
directory.
</para>
<para>
If you have a library installed into <filename>/lib/</filename> and you want
to have it accessible in <filename>/usr/lib/</filename>, then you should
generate a linker script so that the system toolchain can handle it properly.
Please see the <link linkend="qa-missing-ldscript">linker script section</link>
for more information.
</para>
</sect1>
<sect1 id='qa-missing-ldscript'>
<title>Missing Linker Script</title>
<para>
<programlisting>
QA Notice: Missing gen_usr_ldscript
</programlisting>
</para>
<para>
If you have a shared library in <filename>/lib/</filename> and a static
library in <filename>/usr/lib/</filename>, but no linker script in
<filename>/usr/lib/</filename>, then the toolchain will choose the incorrect
version when linking. The system linker will find the static library first
and not bother searching for a dynamic version. To overcome this, you need
to use the <command>gen_usr_ldscript</command> function found in the
toolchain-funcs.eclass. Refer to the
man page for information on how to use it. See this
<ulink url="https://bugs.gentoo.org/4411">bug report</ulink> for some history
on this issue.
</para>
</sect1>
<sect1 id='qa-root-cruft'>
<title>Excessive Files in /</title>
<para>
<programlisting>
QA Notice: Excessive files found in the / partition
</programlisting>
</para>
<para>
You should not store files that are not critical to boot and recovery in
the root filesystem. This means that static libraries and libtool scripts do
not belong in the <filename>/lib/</filename> directory. Fix your ebuild so
it does not install there.
</para>
</sect1>
<sect1 id='qa-tempdir-libtool'>
<title>Portage Tempdir In Libtool Scripts</title>
<para>
<programlisting>
QA Notice: ... appears to contain PORTAGE_TMPDIR paths
</programlisting>
</para>
<para>
Older versions of libtool would incorrectly record the build and/or install
directory in the libtool script (*.la). This would lead to problems when
building other things against your package as libtool would be confused by
the old paths.
</para>
<para>
You may be able to cheat and use the <command>elibtoolize</command> function
in the libtool.eclass. However, if
that does not help, you will probably need to regenerate all of the autotool
files.
</para>
</sect1>
<sect1 id='qa-build-strict-aliasing'>
<title>Build Warning: Strict Aliasing</title>
<para>
<programlisting>
QA Notice: Package has poor programming practices which may compile
fine but exhibit random runtime failures.
...: warning: dereferencing type-punned pointer will break strict-aliasing rules
</programlisting>
</para>
<para>
This warning crops up when code starts casting distinct pointer types and
then dereferencing them. Generally, this is a violation of aliasing rules
which are part of the C standard. Historically, these warnings did not show
up as the optimization was not turned on by default. With gcc-4.1.x and
newer though, the -O2 optimization level enables strict aliasing support.
For information, please review these links:
<ulink url="https://mail-index.netbsd.org/tech-kern/2003/08/11/0001.html">NetBSD Explanation</ulink>,
<ulink url="http://thread.gmane.org/gmane.linux.gentoo.devel/39495">Gentoo Dev Thread</ulink>,
<ulink url="https://gcc.gnu.org/bugs.html#nonbugs_c">GCC Docs</ulink>,
<ulink url="http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html">Practical examples</ulink>.
</para>
<para>
To fix this issue, use the methods proposed in the links mentioned earlier.
If you're unable to do so, then a work around would be to append the gcc
-fno-strict-aliasing flag to CFLAGS in the ebuild.
</para>
</sect1>
<sect1 id='qa-build-implicit-decl'>
<title>Build Warning: Implicit Declarations</title>
<para>
<programlisting>
QA Notice: Package has poor programming practices which may compile
fine but exhibit random runtime failures.
...: warning: implicit declaration of function ...
...: warning: incompatible implicit declaration of built-in function ...
</programlisting>
</para>
<para>
Your code is calling functions which lack prototypes. In C++, this would
have been a build failure, but C is lazy so you just get a warning. This
can be a problem as gcc has to guess at what sort of arguments a function
takes based upon how it was called and often times, this is not the same
as what the function actually takes. The function return type is also
unknown so it's just assumed to be an integer (which is often times wrong).
This can get to be a problem when the size of the types guessed do not
actually match the size of the types the function expects. Generally, this
corresponds directly to proper coding practices (and the lack thereof).
Also, by including proper prototypes, the compiler often helps by checking
types used, proper number of arguments passed, etc...
</para>
<para>
To fix this, just include the proper header files for the functions in
question. If the function is a package-specific one, then you may have to
create a header/function prototype for it.
</para>
</sect1>
<sect1 id='qa-build-uninitialized'>
<title>Build Warning: Used Uninitialized</title>
<para>
<programlisting>
QA Notice: Package has poor programming practices which may compile
fine but exhibit random runtime failures.
...: warning: is used uninitialized in this function
</programlisting>
</para>
<para>
This means code uses a variable without actually setting it first. In other
words, the code is basically using random garbage.
</para>
<para>
The fix here is simple: make sure variables are initialized properly before
using them.
</para>
</sect1>
<sect1 id='qa-build-math-compare'>
<title>Build Warning: Invalid X<=Y<=Z Comparisons</title>
<para>
<programlisting>
QA Notice: Package has poor programming practices which may compile
fine but exhibit random runtime failures.
...: warning: comparisons like X<=Y<=Z do not have their mathematical meaning
</programlisting>
</para>
<para>
This warning crops up either when the programmer expected the expression
to work or they just forgot to use sufficient parentheses. For example,
the following code snippets are wrong (we won't get into the technical
argument of this being valid C code; just change the code to not be
ambiguous).
<programlisting>
if (x <= y <= z)
...;
if (a < b <= c)
...;
</programlisting>
</para>
<para>
To fix this, read the code to figure out what exactly the programmer meant.
</para>
</sect1>
<sect1 id='qa-build-non-null'>
<title>Build Warning: Non-Null Required</title>
<para>
<programlisting>
QA Notice: Package has poor programming practices which may compile
fine but exhibit random runtime failures.
...: warning: null argument where non-null required
</programlisting>
</para>
<para>
Many functions take pointers as arguments and require that the pointer never
be NULL. To this end, you can declare function prototypes that instruct the
compiler to do simple checks to make sure people do not incorrectly call the
function with NULL values. This warning pops up when someone calls a
function and they use NULL when they should not. Depending on the library,
the function may actually crash (they told you not to use NULL after-all, so
it's your fault :P).
</para>
<para>
You will need to read the code and fix it so that it does not incorrectly
call the relevant functions with NULL values.
</para>
</sect1>
<sect1 id='qa-build-pointer-trunc'>
<title>Build Warning: Truncating Pointers</title>
<para>
<programlisting>
QA Notice: Package has poor programming practices which may compile
but will almost certainly crash on 64bit architectures.
</programlisting>
</para>
<para>
A large portion of code in the open source world is developed on the 32bit
x86 architecture. Unfortunately, this has led to many pieces of code not
handling pointer types properly. When compiled and run on a 64bit
architecture, the code in question will probably crash horribly. Some
common examples are assuming that an integer type is large enough to hold
pointers. This is true on 32bit architectures (an integer can hold 32bits
and a pointer is 32bits big), but not true on 64bit architectures (an
integer still holds just 32bits, but a pointer is 64bits big).
</para>
<para>
Since this issue can manifest itself in many ways (as there are many ways to
improperly truncate a pointer), you will need to read the source code
starting with the displayed warning. Make sure types are declared, used,
and passed properly. Make sure that all function prototypes are found (see
the <link linkend="qa-build-implicit-decl">Implicit Declarations</link>
section for more information). So on and so forth.
</para>
</sect1>
</chapter>
</part>
|