The __INO_T_MATCHES_INO64_T is defined
if ino_t would be the same size as ino64_t
if -D_FILE_OFFSET_BITS=64 were not defined.
This is /exactly/ what
/* ABI backwards-compatible shim for non-LFS 32-bit systems */
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && __BITS_PER_LONG < 64
is trying to get at, but currently fails because x32/RV32 are "LFS"
with 32-bit longs and 64-bit time_ts natively.
Thus, the
static_assert(sizeof(unsigned long) == sizeof(__ino_t), "inode size mismatch");
assertion fails (__ino_t is the "kernel ino_t" type,
which generally corresponds to the kernel's ulong, which is u64 on x32).
glibc headers allow us to check the condition we care about directly.
Fixes: commit 9395cc0322 ("Always build for LFS mode on 32-bit archs.")
Closes: #463
Closes: Debian#1098481
Signed-off-by: наб <nabijaczleweli@nabijaczleweli.xyz>
Cc: Alba Mendez <me@alba.sh>
In selinux_restorecon_set_sehandle(), close the old selabel handle
(if it exists) before setting the new one.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Petr Lautrbach <lautrbach@redhat.com>
In case an entry read from a textual fcontext definition is too long set
errno and the error string accordingly.
Fixes: 92306daf ("libselinux: rework selabel_file(5) database")
Reported-by: oss-fuzz (issue 389974971)
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Handle the case where either separated trailing input is empty or non-
existent by initializing the size to 0 and only call related code on
non-zero size.
Fixes: 8997f543 ("libselinux: add selabel_file(5) fuzzer")
Reported-by: oss-fuzz (issue 388319478)
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Update the fuzzers for the input number parameter addition.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Prior the recent selabel_file(5) rework regular expressions for a
certain stem where matched in the order given by the input.
The Reference and Fedora Policy as well as CIL and libsemanage pre-sort
the file context definitions based on the prefix stem length, so this
ordering was adopted.
Do not alter the order by the input of regex specifications, and search
on matches on regex specifications in in parent nodes, which might
contain specifications with definitions defined later in the source
file.
This restores backward compatibility, especially for Android.
Reported-by: Takaya Saeki <takayas@chromium.org>
Closes: https://lore.kernel.org/selinux/CAH9xa6eFO6BNeGko90bsq8CuDba9eO+qdDoF+7zfyAUHEDpH9g@mail.gmail.com/
Fixes: 92306da ("libselinux: rework selabel_file(5) database")
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Commit 89dd0b23 ("libselinux: avoid memory allocation in common file
label lookup") added an additional parameter to lookup_all() for an
optional buffer the return value might be placed into. Update the
fuzzing related code accordingly.
Fixes: 89dd0b23 ("libselinux: avoid memory allocation in common file label lookup")
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Maintains the type signature of the existing matchpathcon_filespec_add()
entry point on 32-bit archs but maps the API to a new
matchpathcon_filespec_add64() entry point that takes a 64-bit ino_t argument
instead.
Software on 32-bit Linux ports which historically use a 32-bit time_t (thus
affected by the y2038 problem) have, as a precondition of migrating to
64-bit time_t, that they also migrate to large filesystem support because
glibc does not provide entry points for the cross-product of
(LFS: yes, LFS: no) x (time_t: 32, time_t: 64).
In order to support smooth migration of such operating systems from 32-bit
time_t to 64-bit time_t, it is useful for libselinux to:
- provide entry points on 32-bit systems for both LFS and non-LFS variants
of the API (as glibc itself does)
- use LFS internally for all filesystem calls (just in case)
- map the API call to the correct implementation based on the build
environment of the caller.
Signed-off-by: Steve Langasek <steve.langasek@canonical.com>
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
The two asserts following qsort(3) where useful during development to
ensure the comparison function and the corresponding pointer handling
were correct. They however do not take into account an empty file
context definition file containing no definitions and thus `stab->nel`
being NULL. Drop the two asserts.
Also return early to not depend on whether calloc(3) called with a size
of zero returns NULL or a special value.
Reported-by: Petr Lautrbach <lautrbach@redhat.com>
Closes: https://lore.kernel.org/selinux/87jzchqck5.fsf@redhat.com/
Fixes: 92306daf ("libselinux: rework selabel_file(5) database")
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Tested-by: Petr Lautrbach <lautrbach@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
Instead of returning directly goto the err label, which prints a message
and closes the opened file stream.
Found by clang-analyzer.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Instead of using asprintf(3) and heavy string formatting just manually
concatenate the substitution string.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Utilize cache locality for the substitutions by storing them in
contiguous memory instead of a linked list.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Remove a memory allocation during a common file label lookup,
e.g. requested by restorecon(8)/setfiles(8), by using a local stack
buffer for a potential lookup result.
Additional minor optimization tweaks.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
If CFLAGS set by the user contains the warnings override
`-Wno-error=implicit-function-declaration` the availability check does
not work properly. Explicitly enable and treat this warnings as failure
by appending the appropriate flag.
Also include CPPFLAGS in the check.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
When building libselinux from its own directory GCC complains about the
two functions free_spec_node() and sort_spec_node(), which are not tiny
and also recursive.
In file included from label_file.c:27:
In function ‘load_mmap’,
inlined from ‘process_file’ at label_file.c:1106:9:
label_file.h:816:20: error: inlining failed in call to ‘free_spec_node’: --param max-inline-insns-single limit reached [-Werror=inline]
816 | static inline void free_spec_node(struct spec_node *node)
| ^~~~~~~~~~~~~~
label_file.c:899:17: note: called from here
899 | free_spec_node(data->root);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
label_file.h:816:20: error: inlining failed in call to ‘free_spec_node’: --param max-inline-insns-single limit reached [-Werror=inline]
816 | static inline void free_spec_node(struct spec_node *node)
| ^~~~~~~~~~~~~~
label_file.c:908:17: note: called from here
908 | free_spec_node(root);
| ^~~~~~~~~~~~~~~~~~~~
In function ‘sort_specs’,
inlined from ‘init’ at label_file.c:1350:3:
label_file.h:404:20: error: inlining failed in call to ‘sort_spec_node’: --param max-inline-insns-single limit reached [-Werror=inline]
404 | static inline void sort_spec_node(struct spec_node *node, struct spec_node *parent)
| ^~~~~~~~~~~~~~
label_file.h:433:9: note: called from here
433 | sort_spec_node(data->root, NULL);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In function ‘sort_specs’,
inlined from ‘init’ at label_file.c:1370:3:
label_file.h:404:20: error: inlining failed in call to ‘sort_spec_node’: --param max-inline-insns-single limit reached [-Werror=inline]
404 | static inline void sort_spec_node(struct spec_node *node, struct spec_node *parent)
| ^~~~~~~~~~~~~~
label_file.h:433:9: note: called from here
433 | sort_spec_node(data->root, NULL);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Fixes: 92306daf ("libselinux: rework selabel_file(5) database")
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
openattr() supplies the simplementation for the getcon(3) interface
family. Use a short local buffer instead of descend into memory
allocation.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Use calloc(3) instead of calling malloc(3) plus a call to memset(3) or
manual zero'ing.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Support the parallel usage of the translated label lookup via
selabel_lookup(3) in multi threaded applications by locking the step
of computing the translated context and the validation state.
A potential use case might can usage from a Rust application via FFI.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Add two fuzzers reading and performing lookup on selabel_file(5)
databases. One fuzzer takes input in form of a textual fcontext
definition, the other one takes compiled fcontexts definitions. The
lookup key and whether to lookup any or a specific file type is also
part of the generated input.
CC: Evgeny Vereshchagin <evverx@gmail.com>
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Due to the selabel_file(5) rework this code is no longer used.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Currently the database for file backend of selabel stores the file
context specifications in a single long array. This array is sorted by
special precedence rules, e.g. regular expressions without meta
character first, ordered by length, and the remaining regular
expressions ordered by stem (the prefix part of the regular expressions
without meta characters) length.
This results in suboptimal lookup performance for two reasons;
File context specifications without any meta characters (e.g.
'/etc/passwd') are still matched via an expensive regular expression
match operation.
All such trivial regular expressions are matched against before any non-
trivial regular expression, resulting in thousands of regex match
operations for lookups for paths not matching any of the trivial ones.
Rework the internal representation of the database in two ways:
Convert regular expressions without any meta characters and containing
only supported escaped characters (e.g. '/etc/rc\.d/init\.d') into
literal strings, which get compared via strcmp(3) later on.
Store the specifications in a tree structure to reduce the to number of
specifications that need to be checked.
Since the internal representation is completely rewritten introduce a
new compiled file context file format mirroring the tree structure.
The new format also stores all multi-byte data in network byte-order, so
that such compiled files can be cross-compiled, e.g. for embedded
devices with read-only filesystems (except for the regular expressions,
which are still architecture-dependent, but ignored on architecture mis-
match).
The improved lookup performance will also benefit SELinux aware daemons,
which create files with their default context, e.g. systemd.
Fedora 41 (pre-compiled regular expressions are omitted on Fedora):
file_contexts.bin: 567248 -> 413191 (bytes)
file_contexts.homedirs.bin: 20677 -> 13107 (bytes)
Debian Sid (pre-compiled regular expressions are included):
file_contexts.bin: 7790690 -> 3646256 (bytes)
file_contexts.homedirs.bin: 835950 -> 708793 (bytes)
(selabel_lookup -b file -k /bin/bash)
Fedora 41 in VM:
text: time: 7.2 ms -> 3.5 ms
peak heap: 2.33M -> 1.81M
peak rss: 6.64M -> 6.37M
compiled: time: 5.9 ms -> 1.6 ms
peak heap: 2.14M -> 1.23M
peak rss: 6.76M -> 5.91M
Debian Sid on Raspberry Pi 3:
text: time: 33.4 ms -> 21.2 ms
peak heap: 10.59M -> 607.32K
peak rss: 6.55M -> 4.46M
compiled: time: 38.3 ms -> 23.5 ms
peak heap: 13.28M -> 2.00M
peak rss: 12.21M -> 7.60M
(restorecon -vRn /)
Fedora 41 in VM:
9.6 s -> 1.3 s
Debian Sid on Raspberry Pi 3:
94.6 s -> 12.1 s
(restorecon -vRn -T0 /)
Fedora 39 in VM (8 cores):
10.9 s -> 1.0 s
Debian Sid on Raspberry Pi 3 (4 cores):
58.9 s -> 12.6 s
(note: I am unsure why the parallel runs on Fedora are slower)
There might be subtle differences in lookup results which evaded my
testing, because some precedence rules are oblique. For example
`/usr/(.*/)?lib(/.*)?` has to have a higher precedence than
`/usr/(.*/)?bin(/.*)?` to match the current Fedora behavior. Please
report any behavior changes.
The maximum node depth in the database is set to 3, which seems to give
the best performance to memory usage ratio. Might be tweaked for
systems with different filesystem hierarchies (Android?).
I am not that familiar with the selabel_partial_match(3),
selabel_get_digests_all_partial_matches(3) and
selabel_hash_all_partial_matches(3) related interfaces, so I only did
some rudimentary tests for them.
CC: Petr Lautrbach <plautrba@redhat.com>
CC: James Carter <jwcart2@gmail.com>
CC: Stephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Add sidtab_context_lookup() to just lookup a context, not inserting
non-existent ones.
Tweak sidtab_destroy() to accept a zero'ed struct sidtab.
Remove redundant lookup in sidtab_context_to_sid() after insertion by
returning the newly created node directly from sidtab_insert().
Drop declaration of only internal used sidtab_insert().
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Reinterpret the currently unused - and always initialized to 1 - member
refcnt of the struct security_id to hold a unique number identifying
the sidtab entry. This identifier can be used instead of the full
context string within other data structures to minimize memory usage.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Use type unsigned for hash values, as returned by sidtab_hash().
Use size_t for buffer length and counting variables.
Constify stats parameter.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Add a utility around selabel_cmp(3).
Can be used by users to compare a pre-compiled fcontext file to an
original text-based file context definition file.
Can be used for development to verify compilation and parsing of the
pre-compiled fcontext format works correctly.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Fixes:
Error: RESOURCE_LEAK (CWE-772):
libselinux-3.6/src/matchpathcon.c:519: alloc_arg: "lgetfilecon_raw" allocates memory that is stored into "con". [Note: The source code implementation of the function has been overridden by a user model.]
libselinux-3.6/src/matchpathcon.c:528: leaked_storage: Variable "con" going out of scope leaks the storage it points to.
\# 526|
\# 527| if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0))
\# 528|-> return -1;
\# 529|
\# 530| if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) {
Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
Fixes:
Error: IDENTICAL_BRANCHES (CWE-398):
libselinux-3.6/src/setexecfilecon.c:45: implicit_else: The code from the above if-then branch is identical to the code after the if statement.
libselinux-3.6/src/setexecfilecon.c:43: identical_branches: The same code is executed when the condition "rc < 0" is true or false, because the code in the if-then branch and after the if statement is identical. Should the if statement be removed?
\# 41|
\# 42| rc = setexeccon(newcon);
\# 43|-> if (rc < 0)
\# 44| goto out;
\# 45| out:
Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
Set errno in open_file() if rolling_append(), which does not set errno,
failed, since transitive callers might rely on it.
Reported-by: clang-analyzer
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Free the allocated line if it fails to parse via process_line() for the
X or media database.
Also declare the line_buf parameter of process_line() const, so it is
more obvious it is not modified or free'd.
Reported-by: clang-analyzer
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
In case fclose(3) might modify the global variable errno, use a wrapper
retaining the errno value. In the affected cases the success of
fclose(3) itself is not important, since the underlying descriptor is
only read from.
Reported-by: clang-analyzer
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
https://github.com/swig/swig/blob/master/CHANGES.current
"[Python] #2907 Fix returning null from functions with output
parameters. Ensures OUTPUT and INOUT typemaps are handled
consistently wrt return type.
New declaration of SWIG_Python_AppendOutput is now:
SWIG_Python_AppendOutput(PyObject* result, PyObject* obj, int is_void);
The 3rd parameter is new and the new $isvoid special variable
should be passed to it, indicating whether or not the wrapped
function returns void.
Also consider replacing with:
SWIG_AppendOutput(PyObject* result, PyObject* obj);
which calls SWIG_Python_AppendOutput with same parameters but adding $isvoid
for final parameter."
Fixes: https://github.com/SELinuxProject/selinux/issues/447
selinuxswig_python_wrap.c: In function ‘_wrap_security_compute_user’:
selinuxswig_python_wrap.c:11499:17: error: too few arguments to function ‘SWIG_Python_AppendOutput’
11499 | resultobj = SWIG_Python_AppendOutput(resultobj, plist);
| ^~~~~~~~~~~~~~~~~~~~~~~~
selinuxswig_python_wrap.c:1248:1: note: declared here
1248 | SWIG_Python_AppendOutput(PyObject* result, PyObject* obj, int is_void) {
| ^~~~~~~~~~~~~~~~~~~~~~~~
selinuxswig_python_wrap.c: In function ‘_wrap_security_compute_user_raw’:
selinuxswig_python_wrap.c:11570:17: error: too few arguments to function ‘SWIG_Python_AppendOutput’
11570 | resultobj = SWIG_Python_AppendOutput(resultobj, plist);
| ^~~~~~~~~~~~~~~~~~~~~~~~
selinuxswig_python_wrap.c:1248:1: note: declared here
1248 | SWIG_Python_AppendOutput(PyObject* result, PyObject* obj, int is_void) {
| ^~~~~~~~~~~~~~~~~~~~~~~~
selinuxswig_python_wrap.c: In function ‘_wrap_security_get_boolean_names’:
selinuxswig_python_wrap.c:12470:17: error: too few arguments to function ‘SWIG_Python_AppendOutput’
12470 | resultobj = SWIG_Python_AppendOutput(resultobj, list);
| ^~~~~~~~~~~~~~~~~~~~~~~~
selinuxswig_python_wrap.c:1248:1: note: declared here
1248 | SWIG_Python_AppendOutput(PyObject* result, PyObject* obj, int is_void) {
| ^~~~~~~~~~~~~~~~~~~~~~~~
error: command '/usr/bin/gcc' failed with exit code 1
Suggested-by: Jitka Plesnikova <jplesnik@redhat.com>
Signed-off-by: Petr Lautrbach <lautrbach@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
It was originally marked for deprecation back in Feb 2020,
commit a41dfeb55d ("libselinux: deprecate security_compute_user(),
update man pages"), but the attribute was not added at the time.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Acked-by: Petr Lautrbach <lautrbach@redhat.com>
In commit d95bc8b755 ("libselinux: migrating hashtab from
policycoreutils") and commit 4a420508a9 ("libselinux: adapting hashtab
to libselinux"), the hashtab implementation was copied to libselinux.
Since the same functions exist in libsepol (e.g., hashtab_create,
hashtab_destroy, etc), a compilation error is raised when both libraries
are included statically.
Prefix the libselinux internal implementation with "selinux_".
Signed-off-by: Thiébaud Weksteen <tweek@google.com>
Acked-by: James Carter <jwcart2@gmail.com>
The runtime disable functionality has been removed in Linux 6.4. Thus
security_disable(3) will no longer work on these kernels.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Trying to compile libselinux for 32-bit produces the following error:
selinux_restorecon.c:1194:31: error: comparison of integer expressions of different signedness: ‘__fsword_t’ {aka ‘int’} and ‘unsigned int’ [-Werror=sign-compare]
1194 | if (state.sfsb.f_type == RAMFS_MAGIC || state.sfsb.f_type == TMPFS_MAGIC ||
| ^~
Since RAMFS_MAGIC = 0x858458f6 == 2240043254, which > 2^31, but < 2^32,
cast both as uint32_t for the comparison.
Reported-by: Daniel Schepler
Signed-off-by: James Carter <jwcart2@gmail.com>
Reviewed-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
restorecon.h uses types defined in label.h, so it needs to include
label.h (or code using restorecon.h also needs to include label.h,
which is not practical).
Fixes:
$ make DESTDIR=~/obj install > make.out
In file included from semanage_store.c:39:
/home/sdsmall/obj/usr/include/selinux/restorecon.h:137:52: error:
‘struct selabel_handle’ declared inside parameter list will not be
visible outside of this definition or declaration [-Werror]
137 | extern void selinux_restorecon_set_sehandle(struct
selabel_handle *hndl);
| ^~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[2]: *** [Makefile:111: semanage_store.o] Error 1
make[1]: *** [Makefile:15: install] Error 2
make: *** [Makefile:40: install] Error 1
Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Fixes segfault in selabel_open() on systems with SELinux disabled and without any
SELinux policy installed introduced by commit 5876aca048 ("libselinux: free
data on selabel open failure"):
$ sestatus
SELinux status: disabled
$ cat /etc/selinux/config
cat: /etc/selinux/config: No such file or directory
$ matchpathcon /abc
[1] 907999 segmentation fault (core dumped) matchpathcon /abc
Signed-off-by: Petr Lautrbach <lautrbach@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
The option array passed to avc_open(3) is only read from.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Since commit 5876aca0 ("libselinux: free data on selabel open failure")
the close handler of label backends must support partial initialized
state, e.g. ->data being NULL. Thus checks for NULL were added, but in
two cases the pointers in question were already dereferenced before.
Reorder the dereference after the NULL-checks.
Fixes: 5876aca0 ("libselinux: free data on selabel open failure")
Reported-by: Cppcheck
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
In case scandir(3) finds no entries still free the returned result to
avoid leaking it.
Also do not override errno in case of a failure.
Reported.by: Cppcheck
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>