Skip to content

Commit

Permalink
Create libqubes-pure: a library of Qubes-specific code that does no I/O
Browse files Browse the repository at this point in the history
Currently this only includes functions for sanitizing strings and paths,
but future versions will also support validating qube names, qrexec
service names and arguments, and possibly more.  The header file also
includes types for string buffers and extensive documentation.
  • Loading branch information
DemiMarie committed Mar 10, 2023
1 parent b177446 commit b7b4461
Show file tree
Hide file tree
Showing 8 changed files with 550 additions and 359 deletions.
2 changes: 2 additions & 0 deletions debian/libqubes-rpc-filecopy-dev.install
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
usr/include/libqubes-rpc-filecopy.h
usr/include/qubes/pure.h
usr/lib/libqubes-rpc-filecopy.so
usr/lib/libqubes-pure.so
1 change: 1 addition & 0 deletions debian/libqubes-rpc-filecopy2.install
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
usr/lib/libqubes-rpc-filecopy.so.2*
usr/lib/libqubes-pure.so.0*
1 change: 1 addition & 0 deletions debian/libqubes-rpc-filecopy2.shlibs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
libqubes-rpc-filecopy 2 libqubes-rpc-filecopy2 (>= 4.1.7)
libqubes-pure 0 libqubes-rpc-filecopy2 (>= 4.2.0)
38 changes: 25 additions & 13 deletions qrexec-lib/Makefile
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
CC=gcc
CFLAGS+=-I. -g -O2 -Wall -Wextra -Werror -pie -fPIC $(shell pkg-config --cflags icu-uc)
CFLAGS := $(CFLAGS) -I. -g -O2 -Wall -Wextra -Werror -pie -fPIC $(shell pkg-config --cflags icu-uc)
SO_VER=2
LDFLAGS+=-shared
LDLIBS += $(shell pkg-config --libs icu-uc)
LDFLAGS+=-shared -Wl,--no-undefined,--as-needed
pure_libs := $(shell pkg-config --libs icu-uc)
.PHONY: all clean install
objs := ioall.o copy-file.o crc32.o unpack.o pack.o

all: libqubes-rpc-filecopy.so.$(SO_VER)
libqubes-rpc-filecopy.so.$(SO_VER): $(objs)
pure_lib := libqubes-pure.so
pure_sover := 0
pure_objs := unicode.o

all: libqubes-rpc-filecopy.so.$(SO_VER) $(pure_lib).$(pure_sover)
libqubes-rpc-filecopy.so.$(SO_VER): $(objs) ./$(pure_lib).$(pure_sover)
$(CC) $(LDFLAGS) -Wl,-soname,$@ -o $@ $^ $(LDLIBS)
$(pure_objs): CFLAGS += -fvisibility=hidden -DQUBES_PURE_IMPLEMENTATION

$(pure_lib).$(pure_sover): $(pure_objs)
$(CC) $(LDFLAGS) -Wl,-Bsymbolic,-soname,$@ -o $@ $^ $(pure_libs)

%.o: %.c
%.o: %.c Makefile
$(CC) $(CFLAGS) -MD -MP -MF $@.dep -c -o $@ $<
unpack.o: unpack-table.c
unpack-table.c: gentbl.py
python3 gentbl.py > unpack-table.c

unicode.o: unicode-class-table.c
unicode-class-table.c: gentbl.py Makefile
python3 -- $< > $@

%.a: $(objs)
$(AR) rcs $@ $^
clean:
rm -f *.o *~ *.a *.so.*
rm -f ./*.o ./*~ ./*.a ./*.so.* ./*.dep unicode-class-table.c

install:
mkdir -p $(DESTDIR)$(LIBDIR)
cp libqubes-rpc-filecopy.so.$(SO_VER) $(DESTDIR)$(LIBDIR)
ln -s libqubes-rpc-filecopy.so.$(SO_VER) $(DESTDIR)$(LIBDIR)/libqubes-rpc-filecopy.so
mkdir -p $(DESTDIR)$(INCLUDEDIR)
install libqubes-rpc-filecopy.so.$(SO_VER) $(DESTDIR)$(LIBDIR)
ln -sf libqubes-rpc-filecopy.so.$(SO_VER) $(DESTDIR)$(LIBDIR)/libqubes-rpc-filecopy.so
install $(pure_lib).$(pure_sover) $(DESTDIR)$(LIBDIR)
ln -sf $(pure_lib).$(pure_sover) $(DESTDIR)$(LIBDIR)/$(pure_lib)
mkdir -p $(DESTDIR)$(INCLUDEDIR)/qubes
cp libqubes-rpc-filecopy.h $(DESTDIR)$(INCLUDEDIR)
cp pure.h $(DESTDIR)$(INCLUDEDIR)/qubes
-include ./*.o.dep
124 changes: 124 additions & 0 deletions qrexec-lib/pure.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#ifndef QUBES_UTIL_PURE_H
#define QUBES_UTIL_PURE_H QUBES_UTIL_PURE_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

#if defined QUBES_EXPORT
# error QUBES_EXPORT already defined
#elif defined _WIN32 || defined __CYGWIN__
# ifdef _MSC_VER
# define QUBES_EXPORT __declspec(dllexport)
# define QUBES_IMPORT __declspec(dllimport)
# elif defined __GNUC__
# define QUBES_EXPORT __attribute__(dllexport)
# define QUBES_EXPORT __attribute__(dllimport)
# else
# error unknown C compiler for Windows target
# endif
#elif defined __has_attribute
# if __has_attribute(visibility)
# define QUBES_EXPORT __attribute__((visibility("default")))
# define QUBES_IMPORT __attribute__((visibility("default")))
# elif defined __clang__
# error clang always supports visibility
# endif
#elif defined __GNUC__ && __GNUC__ >= 4
# define QUBES_EXPORT __attribute__((visibility("default")))
# define QUBES_IMPORT __attribute__((visibility("default")))
#endif

#ifndef QUBES_EXPORT
# if (defined __clang__) || (defined __GNUC__ && __GNUC__ >= 4) || defined _MSC_VER
# error This compiler should support visibility but does not
# endif
# define QUBES_EXPORT /* nothing */
# define QUBES_IMPORT /* nothing */
#endif

#ifdef QUBES_PURE_IMPLEMENTATION
# define QUBES_PURE_PUBLIC QUBES_EXPORT
#else
# define QUBES_PURE_PUBLIC QUBES_IMPORT
#endif

/**
* A counted buffer used by some functions in this library.
* Equivalent to Rust's &[T].
*/
struct QubesSlice {
/// Pointer to the data
const uint8_t *untrusted_pointer;
/// Length of the data
size_t length;
} __attribute__((may_alias));

/** A mutable slice. Equivalent to Rust's &mut [T]. */
struct QubesMutableSlice {
/// Pointer to the data
uint8_t *untrusted_pointer;
/// Length of the data
size_t length;
} __attribute__((may_alias));

/**
* Validate that a string is a valid path and will not result in
* directory traversal if used as such. Characters that are unsafe for
* filenames are also rejected, including invalid UTF-8 sequences and
* all control characters. The input must be NUL-terminated.
*
* Returns true on success and false on failure.
*/
QUBES_PURE_PUBLIC bool
qubes_pure_validate_file_name(const char *untrusted_filename);

/**
* Validate that `untrusted_name` is a valid symbolic link name
* and that creating a symbolic link with that name and target
* `untrusted_target` is also safe. Characters that are unsafe for
* filenames are also rejected, including invalid UTF-8
* sequences and all control characters. The input must be
* NUL-terminated.
*
* Returns true on success and false on failure.
*/
QUBES_PURE_PUBLIC bool
qubes_pure_validate_symbolic_link(const char *untrusted_name,
const char *untrusted_target);

/**
* Validate that `untrusted_str` is safe to display. To be considered safe to
* display, a string must be valid UTF-8 and contain no control characters
* except perhaps newline. The string must also contain no characters that
* are complex to render and thus significantly increase the attack surface
* of text rendering libraries such as Fribidi, Harfbuzz, or Pango. The set
* of characters that are considered complex to render is implementation
* dependent and may change in future versions of this library. Currenty,
* it includes the following:
*
* - Characters that have a character direction property other than
* WHITE_SPACE_NEUTRAL, OTHRE_NEUTRAL, EUROPEAN_NUMBER_TERMINATOR,
* EUROPEAN_NUMBER_SEPARATOR, COMMON_NUMBER_SEPARATOR, or LEFT_TO_RIGHT.
*
* - Characters that are part of scripts that are not recommended for use
* in identifiers. This includes limited-use scripts.
*
* - Characters with scripts that are not INHERITED, CYRILLIC, GREEK, LATIN,
* BRAILLE, SIMPLIFIED_HAN, TRADITIONAL_HAN, HAN, HAN_WITH_BOPOMOFO, JAMO,
* HANGUL, BOPOMOFO, KATAKANA_OR_HIRAGANA, HIRIGANA, KATAKANA, JAPANESE,
* KOREAN, or COMMON.
*
* \param untrusted_str The string to be validated. Must be NUL-terminated
* but is otherwise untrusted.
*
* \param line_length The maximum length of a line. If zero, no line breaks
* are allowed. Otherwise, at most line_length characters can occur without
* an intervening newline, and a trailing newline is required.
*
* \note Currently, nonzero `line_length` is not implemented and will cause
* an assertion failure.
*/
QUBES_PURE_PUBLIC bool
qubes_pure_check_string_safe_for_display(const char *untrusted_str,
size_t line_length);
#endif // !defined QUBES_UTIL_PURE_H
Loading

0 comments on commit b7b4461

Please sign in to comment.