ci/woodpecker/push/woodpecker Pipeline was successfulDetails
fix https://github.com/pkgconf/pkgconf/issues/291
As defined in the C standard:
In all cases the argument is an int, the value of which shall
be representable as an unsigned char or shall equal the value
of the macro EOF. If the argument has any other value, the
behavior is undefined.
This is because they're designed to work with the int values returned
by getc or fgetc; they need extra work to handle a char value.
If EOF is -1 (as it almost always is), with 8-bit bytes, the allowed
inputs to the ctype(3) functions are:
{-1, 0, 1, 2, 3, ..., 255}.
However, on platforms where char is signed, such as x86 with the
usual ABI, code like
char *ptr = ...;
... isspace(*ptr) ...
may pass in values in the range:
{-128, -127, -126, ..., -2, -1, 0, 1, ..., 127}.
This has two problems:
1. Inputs in the set {-128, -127, -126, ..., -2} are forbidden.
2. The non-EOF byte 0xff is conflated with the value EOF = -1, so
even though the input is not forbidden, it may give the wrong
answer.
Casting char to unsigned int first before passing the result to
ctype(3) doesn't help: inputs like -128 are unchanged by this cast,
because (on a two's-complement machine with 32-bit int and unsigned
int), converting the signed char with integer value -128 to unsigned
int gives integer value 2^32 - 128 = 0xffffff80, which is out of
range, and which is converted in int back to -128, which is also out
of range.
It is necessary to cast char inputs to unsigned char first; you can
then cast to unsigned int if you like but there's no need because the
functions will always convert the argument to int by definition. So
the above fragment needs to be:
char *ptr = ...;
... isspace((unsigned char)*ptr) ...
This patch changes unsigned int casts to unsigned char casts, and
adds unsigned char casts where they are missing.
We only want a reference to be added for the value inserted into the
list, not the one returned. The returned one is unowned until it reaches
the public dependency_add function, which returns an owned pointer
instead. This makes things semantically more correct.
Unfortunately, this means in a few cases we have to write some ugly
code like:
```c
pkgconf_dependency_t *dep = pkgcond_dependency_add("args");
pkgconf_dependency_unref(dep->owner, dep);
```
It is possible to trigger an out of boundary write in function
pkgconf_dependency_parse_str if a dependency line contains a very
long comparator. The comparator is stored in a temporary buffer which
has a size of PKGCONF_ITEM_SIZE.
The line which is parsed can be up to PKGCONF_BUFSIZE characters long,
which is larger than PKGCONF_ITEM_SIZE (although it depends on PATH_MAX).
Having a comparator which is longer than PKGCONF_ITEM_SIZE therefore
leads to an out of boundary write. Although it is undefined behaviour,
this can lead to an overridden compare variable, which in turn can lead
to an invalid instruction pointer, i.e. most likely a crash or code
execution (very unlikely).
Proof of concept:
$ echo "Requires: x " > poc.pc
$ dd if=/dev/zero bs=1 count=65535 | tr '\0' '<' >> poc.pc
$ pkgconf poc.pc
Eiter compile pkgconf with address sanitizer or run pkgconf multiple
times, eventually it might crash (assuming that ASLR is in place).
In order to fix this, I decided to use an end pointer to avoid OOB write.
Alternative would be to increase the buffer size, but I try to avoid that
since this would be additional ~60 KB stack space for a very unlikely
situation.
in almost all cases, we partially solve the dependency graph multiple times, which
just wastes resources. if we record the solution to a given dependency node, further
iterations can make use of the previous solution without having to solve it again.
this is safe because all provides entries (including virtuals) are knowable prior to
solving the dependency graph the first time.
a nice side effect of this is that all packages are preloaded when querying
information about them (--cflags and related commands).
* remove dead assignments
None of them are used.
Signed-off-by: Igor Gnatenko <ignatenko@redhat.com>
* The address of an object "&pkgconf_pkg_provides_vermatch_rules[pkgdep->compare]" is never null
Signed-off-by: Igor Gnatenko <ignatenko@redhat.com>
* Overrunning array pkgconf_pkg_comparator_names at element index 7
Signed-off-by: Igor Gnatenko <ignatenko@redhat.com>