diff mbox series

[v5] Allow to build and run sign/digest on Windows

Message ID 20201221221953.256059-1-bluca@debian.org (mailing list archive)
State Superseded
Headers show
Series [v5] Allow to build and run sign/digest on Windows | expand

Commit Message

Luca Boccassi Dec. 21, 2020, 10:19 p.m. UTC
From: Luca Boccassi <luca.boccassi@microsoft.com>

Add some minimal compat type defs, and stub out the enable/measure
sources. Also add a way to handle the fact that mingw adds a
.exe extension automatically in the Makefile install rules.

Signed-off-by: Luca Boccassi <luca.boccassi@microsoft.com>
---
v2: rework the stubbing out to detect mingw in the Makefile and remove
    sources from compilation, instead of ifdefs.
    add a new common/win32_defs.h for the compat definitions.
    define strerror_r using strerror_s.

    To compile with mingw:
      make CC=x86_64-w64-mingw32-gcc-8.3-win32
    note that the openssl headers and a win32 libcrypto.dll need
    to be available in the default search paths, and otherwise have
    to be specified as expected via CPPFLAGS/LDFLAGS
v3: apply suggestion to remove -D_GNU_SOURCE from the header and define
    it as a CPPFLAGS, and to add  a definition of __printf for _WIN32
    to fix compiler warnings
    removed override of -lcrypto, not needed
v4: apply suggestion to remove overrides of %zu, as it now "just works".
    no more compilation warnings.
v5: change makefile fsverity target to use $(EXEEXT), and ensure make check
    can run under Windows (tested with wine, using TEST_WRAPPER_PROG=wine)

 Makefile               | 48 +++++++++++++++++++++++------------
 common/common_defs.h   |  2 ++
 common/fsverity_uapi.h |  2 ++
 common/win32_defs.h    | 57 ++++++++++++++++++++++++++++++++++++++++++
 lib/utils.c            | 11 ++++++--
 programs/fsverity.c    |  2 ++
 programs/utils.c       |  2 +-
 7 files changed, 105 insertions(+), 19 deletions(-)
 create mode 100644 common/win32_defs.h

Comments

Eric Biggers Dec. 21, 2020, 11:03 p.m. UTC | #1
On Mon, Dec 21, 2020 at 10:19:53PM +0000, Luca Boccassi wrote:
> From: Luca Boccassi <luca.boccassi@microsoft.com>
> 
> stub out the enable/measure sources.

That's not the case anymore, right?  Now those files are just omitted.

> diff --git a/Makefile b/Makefile
> index bfe83c4..d850ae3 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -35,6 +35,11 @@
>  cc-option = $(shell if $(CC) $(1) -c -x c /dev/null -o /dev/null > /dev/null 2>&1; \
>  	      then echo $(1); fi)
>  
> +# Support building with MinGW for minimal Windows fsverity.exe
> +ifneq ($(findstring -mingw,$(shell $(CC) -dumpmachine 2>/dev/null)),)
> +MINGW = 1
> +endif

It would be helpful if this comment mentioned that libfsverity isn't built as a
proper Windows library.  At the moment it is not very clear.

Also, a note in the README about the Windows support would be helpful.

> -override CPPFLAGS := -Iinclude -D_FILE_OFFSET_BITS=64 $(CPPFLAGS)
> +override CPPFLAGS := -Iinclude -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(CPPFLAGS)

The _GNU_SOURCE change should go in a separate patch.

>  # Rebuild if a user-specified setting that affects the build changed.
>  .build-config: FORCE
> @@ -87,9 +97,9 @@ CFLAGS          += $(shell "$(PKGCONF)" libcrypto --cflags 2>/dev/null || echo)
>  # If we are dynamically linking, when running tests we need to override
>  # LD_LIBRARY_PATH as no RPATH is set
>  ifdef USE_SHARED_LIB
> -RUN_FSVERITY    = LD_LIBRARY_PATH=./ ./fsverity
> +RUN_FSVERITY    = LD_LIBRARY_PATH=./ $(TEST_WRAPPER_PROG) ./fsverity$(EXEEXT)
>  else
> -RUN_FSVERITY    = ./fsverity
> +RUN_FSVERITY    = $(TEST_WRAPPER_PROG) ./fsverity$(EXEEXT)
>  endif

Adding $(TEST_WRAPPER_PROG) here should go in a separate patch too.  It also
affects valgrind testing on Linux.

>  # Link the fsverity program
>  ifdef USE_SHARED_LIB
> -fsverity: $(FSVERITY_PROG_OBJ) libfsverity.so
> +fsverity$(EXEEXT): $(FSVERITY_PROG_OBJ) libfsverity.so

It would be easier to read if there was a variable $(FSVERITY) that had the
value of fsverity$(EXEEXT).

>  # Link the test programs
>  $(TEST_PROGRAMS): %: programs/%.o $(PROG_COMMON_OBJ) libfsverity.a
> @@ -184,25 +200,25 @@ test_programs:$(TEST_PROGRAMS)

This still doesn't actually add the .exe extension to the test programs.
Try 'make CC=x86_64-w64-mingw32-gcc help'; the targets to build the test
programs don't have the .exe extension.

- Eric
Luca Boccassi Dec. 21, 2020, 11:26 p.m. UTC | #2
On Mon, 21 Dec 2020 at 23:03, Eric Biggers <ebiggers@kernel.org> wrote:
>
> On Mon, Dec 21, 2020 at 10:19:53PM +0000, Luca Boccassi wrote:
> > From: Luca Boccassi <luca.boccassi@microsoft.com>
> >
> > stub out the enable/measure sources.
>
> That's not the case anymore, right?  Now those files are just omitted.

Clarified in v6

> > diff --git a/Makefile b/Makefile
> > index bfe83c4..d850ae3 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -35,6 +35,11 @@
> >  cc-option = $(shell if $(CC) $(1) -c -x c /dev/null -o /dev/null > /dev/null 2>&1; \
> >             then echo $(1); fi)
> >
> > +# Support building with MinGW for minimal Windows fsverity.exe
> > +ifneq ($(findstring -mingw,$(shell $(CC) -dumpmachine 2>/dev/null)),)
> > +MINGW = 1
> > +endif
>
> It would be helpful if this comment mentioned that libfsverity isn't built as a
> proper Windows library.  At the moment it is not very clear.
>
> Also, a note in the README about the Windows support would be helpful.

Done both in v6

> > -override CPPFLAGS := -Iinclude -D_FILE_OFFSET_BITS=64 $(CPPFLAGS)
> > +override CPPFLAGS := -Iinclude -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(CPPFLAGS)
>
> The _GNU_SOURCE change should go in a separate patch.

Split out in v6

> >  # Rebuild if a user-specified setting that affects the build changed.
> >  .build-config: FORCE
> > @@ -87,9 +97,9 @@ CFLAGS          += $(shell "$(PKGCONF)" libcrypto --cflags 2>/dev/null || echo)
> >  # If we are dynamically linking, when running tests we need to override
> >  # LD_LIBRARY_PATH as no RPATH is set
> >  ifdef USE_SHARED_LIB
> > -RUN_FSVERITY    = LD_LIBRARY_PATH=./ ./fsverity
> > +RUN_FSVERITY    = LD_LIBRARY_PATH=./ $(TEST_WRAPPER_PROG) ./fsverity$(EXEEXT)
> >  else
> > -RUN_FSVERITY    = ./fsverity
> > +RUN_FSVERITY    = $(TEST_WRAPPER_PROG) ./fsverity$(EXEEXT)
> >  endif
>
> Adding $(TEST_WRAPPER_PROG) here should go in a separate patch too.  It also
> affects valgrind testing on Linux.

Split out in v6

> >  # Link the fsverity program
> >  ifdef USE_SHARED_LIB
> > -fsverity: $(FSVERITY_PROG_OBJ) libfsverity.so
> > +fsverity$(EXEEXT): $(FSVERITY_PROG_OBJ) libfsverity.so
>
> It would be easier to read if there was a variable $(FSVERITY) that had the
> value of fsverity$(EXEEXT).

Done in v6

> >  # Link the test programs
> >  $(TEST_PROGRAMS): %: programs/%.o $(PROG_COMMON_OBJ) libfsverity.a
> > @@ -184,25 +200,25 @@ test_programs:$(TEST_PROGRAMS)
>
> This still doesn't actually add the .exe extension to the test programs.
> Try 'make CC=x86_64-w64-mingw32-gcc help'; the targets to build the test
> programs don't have the .exe extension.

Yeah it didn't show in the target - although the binaries do have the
extension. Should be all fixed now in v6.

Kind regards,
Luca Boccassi
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index bfe83c4..d850ae3 100644
--- a/Makefile
+++ b/Makefile
@@ -35,6 +35,11 @@ 
 cc-option = $(shell if $(CC) $(1) -c -x c /dev/null -o /dev/null > /dev/null 2>&1; \
 	      then echo $(1); fi)
 
+# Support building with MinGW for minimal Windows fsverity.exe
+ifneq ($(findstring -mingw,$(shell $(CC) -dumpmachine 2>/dev/null)),)
+MINGW = 1
+endif
+
 CFLAGS ?= -O2
 
 override CFLAGS := -Wall -Wundef				\
@@ -47,7 +52,7 @@  override CFLAGS := -Wall -Wundef				\
 	$(call cc-option,-Wvla)					\
 	$(CFLAGS)
 
-override CPPFLAGS := -Iinclude -D_FILE_OFFSET_BITS=64 $(CPPFLAGS)
+override CPPFLAGS := -Iinclude -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(CPPFLAGS)
 
 ifneq ($(V),1)
 QUIET_CC        = @echo '  CC      ' $@;
@@ -62,7 +67,12 @@  BINDIR          ?= $(PREFIX)/bin
 INCDIR          ?= $(PREFIX)/include
 LIBDIR          ?= $(PREFIX)/lib
 DESTDIR         ?=
+ifneq ($(MINGW),1)
 PKGCONF         ?= pkg-config
+else
+PKGCONF         := false
+EXEEXT          := .exe
+endif
 
 # Rebuild if a user-specified setting that affects the build changed.
 .build-config: FORCE
@@ -87,9 +97,9 @@  CFLAGS          += $(shell "$(PKGCONF)" libcrypto --cflags 2>/dev/null || echo)
 # If we are dynamically linking, when running tests we need to override
 # LD_LIBRARY_PATH as no RPATH is set
 ifdef USE_SHARED_LIB
-RUN_FSVERITY    = LD_LIBRARY_PATH=./ ./fsverity
+RUN_FSVERITY    = LD_LIBRARY_PATH=./ $(TEST_WRAPPER_PROG) ./fsverity$(EXEEXT)
 else
-RUN_FSVERITY    = ./fsverity
+RUN_FSVERITY    = $(TEST_WRAPPER_PROG) ./fsverity$(EXEEXT)
 endif
 
 ##############################################################################
@@ -99,6 +109,9 @@  endif
 SOVERSION       := 0
 LIB_CFLAGS      := $(CFLAGS) -fvisibility=hidden
 LIB_SRC         := $(wildcard lib/*.c)
+ifeq ($(MINGW),1)
+LIB_SRC         := $(filter-out lib/enable.c,${LIB_SRC})
+endif
 LIB_HEADERS     := $(wildcard lib/*.h) $(COMMON_HEADERS)
 STATIC_LIB_OBJ  := $(LIB_SRC:.c=.o)
 SHARED_LIB_OBJ  := $(LIB_SRC:.c=.shlib.o)
@@ -141,10 +154,13 @@  PROG_COMMON_SRC   := programs/utils.c
 PROG_COMMON_OBJ   := $(PROG_COMMON_SRC:.c=.o)
 FSVERITY_PROG_OBJ := $(PROG_COMMON_OBJ)		\
 		     programs/cmd_digest.o	\
-		     programs/cmd_enable.o	\
-		     programs/cmd_measure.o	\
 		     programs/cmd_sign.o	\
 		     programs/fsverity.o
+ifneq ($(MINGW),1)
+FSVERITY_PROG_OBJ += \
+		     programs/cmd_enable.o	\
+		     programs/cmd_measure.o
+endif
 TEST_PROG_SRC     := $(wildcard programs/test_*.c)
 TEST_PROGRAMS     := $(TEST_PROG_SRC:programs/%.c=%)
 
@@ -154,15 +170,15 @@  $(ALL_PROG_OBJ): %.o: %.c $(ALL_PROG_HEADERS) .build-config
 
 # Link the fsverity program
 ifdef USE_SHARED_LIB
-fsverity: $(FSVERITY_PROG_OBJ) libfsverity.so
+fsverity$(EXEEXT): $(FSVERITY_PROG_OBJ) libfsverity.so
 	$(QUIET_CCLD) $(CC) -o $@ $(FSVERITY_PROG_OBJ) \
 		$(CFLAGS) $(LDFLAGS) -L. -lfsverity
 else
-fsverity: $(FSVERITY_PROG_OBJ) libfsverity.a
+fsverity$(EXEEXT): $(FSVERITY_PROG_OBJ) libfsverity.a
 	$(QUIET_CCLD) $(CC) -o $@ $+ $(CFLAGS) $(LDFLAGS) $(LDLIBS)
 endif
 
-DEFAULT_TARGETS += fsverity
+DEFAULT_TARGETS += fsverity$(EXEEXT)
 
 # Link the test programs
 $(TEST_PROGRAMS): %: programs/%.o $(PROG_COMMON_OBJ) libfsverity.a
@@ -184,25 +200,25 @@  test_programs:$(TEST_PROGRAMS)
 
 # This just runs some quick, portable tests.  Use scripts/run-tests.sh if you
 # want to run the full tests.
-check:fsverity test_programs
+check:fsverity$(EXEEXT) test_programs
 	for prog in $(TEST_PROGRAMS); do \
-		$(TEST_WRAPPER_PROG) ./$$prog || exit 1; \
+		$(TEST_WRAPPER_PROG) ./$$prog$(EXEEXT) || exit 1; \
 	done
 	$(RUN_FSVERITY) --help > /dev/null
 	$(RUN_FSVERITY) --version > /dev/null
-	$(RUN_FSVERITY) sign fsverity fsverity.sig \
+	$(RUN_FSVERITY) sign fsverity$(EXEEXT) fsverity.sig \
 		--key=testdata/key.pem --cert=testdata/cert.pem > /dev/null
-	$(RUN_FSVERITY) sign fsverity fsverity.sig --hash=sha512 \
+	$(RUN_FSVERITY) sign fsverity$(EXEEXT) fsverity.sig --hash=sha512 \
 		--block-size=512 --salt=12345678 \
 		--key=testdata/key.pem --cert=testdata/cert.pem > /dev/null
-	$(RUN_FSVERITY) digest fsverity --hash=sha512 \
+	$(RUN_FSVERITY) digest fsverity$(EXEEXT) --hash=sha512 \
 		--block-size=512 --salt=12345678 > /dev/null
 	rm -f fsverity.sig
 	@echo "All tests passed!"
 
 install:all
 	install -d $(DESTDIR)$(LIBDIR)/pkgconfig $(DESTDIR)$(INCDIR) $(DESTDIR)$(BINDIR)
-	install -m755 fsverity $(DESTDIR)$(BINDIR)
+	install -m755 fsverity$(EXEEXT) $(DESTDIR)$(BINDIR)
 	install -m644 libfsverity.a $(DESTDIR)$(LIBDIR)
 	install -m755 libfsverity.so.$(SOVERSION) $(DESTDIR)$(LIBDIR)
 	ln -sf libfsverity.so.$(SOVERSION) $(DESTDIR)$(LIBDIR)/libfsverity.so
@@ -215,7 +231,7 @@  install:all
 	chmod 644 $(DESTDIR)$(LIBDIR)/pkgconfig/libfsverity.pc
 
 uninstall:
-	rm -f $(DESTDIR)$(BINDIR)/fsverity
+	rm -f $(DESTDIR)$(BINDIR)/fsverity$(EXEEXT)
 	rm -f $(DESTDIR)$(LIBDIR)/libfsverity.a
 	rm -f $(DESTDIR)$(LIBDIR)/libfsverity.so.$(SOVERSION)
 	rm -f $(DESTDIR)$(LIBDIR)/libfsverity.so
@@ -232,4 +248,4 @@  help:
 
 clean:
 	rm -f $(DEFAULT_TARGETS) $(TEST_PROGRAMS) \
-		lib/*.o programs/*.o .build-config fsverity.sig
+		lib/*.o programs/*.o .build-config fsverity.sig *.exe
diff --git a/common/common_defs.h b/common/common_defs.h
index 279385a..3ae5561 100644
--- a/common/common_defs.h
+++ b/common/common_defs.h
@@ -15,6 +15,8 @@ 
 #include <stddef.h>
 #include <stdint.h>
 
+#include "win32_defs.h"
+
 typedef uint8_t u8;
 typedef uint16_t u16;
 typedef uint32_t u32;
diff --git a/common/fsverity_uapi.h b/common/fsverity_uapi.h
index 33f4415..be1d3f6 100644
--- a/common/fsverity_uapi.h
+++ b/common/fsverity_uapi.h
@@ -10,8 +10,10 @@ 
 #ifndef _UAPI_LINUX_FSVERITY_H
 #define _UAPI_LINUX_FSVERITY_H
 
+#ifndef _WIN32
 #include <linux/ioctl.h>
 #include <linux/types.h>
+#endif /* _WIN32 */
 
 #define FS_VERITY_HASH_ALG_SHA256	1
 #define FS_VERITY_HASH_ALG_SHA512	2
diff --git a/common/win32_defs.h b/common/win32_defs.h
new file mode 100644
index 0000000..29ef9b2
--- /dev/null
+++ b/common/win32_defs.h
@@ -0,0 +1,57 @@ 
+/* SPDX-License-Identifier: MIT */
+/*
+ * WIN32 compat definitions for libfsverity and the 'fsverity' program
+ *
+ * Copyright 2020 Microsoft
+ *
+ * Use of this source code is governed by an MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT.
+ */
+#ifndef COMMON_WIN32_DEFS_H
+#define COMMON_WIN32_DEFS_H
+
+/* Some minimal definitions to allow the digest/sign commands to run under Windows */
+
+/* All file reads we do need this flag on _WIN32 */
+#ifndef O_BINARY
+#  define O_BINARY 0
+#endif
+
+#ifdef _WIN32
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#ifndef ENOPKG
+#   define ENOPKG 65
+#endif
+
+#ifndef __cold
+#  define __cold
+#endif
+
+/* For %zu in printf() */
+#ifndef __printf
+#  define __printf(fmt_idx, vargs_idx) \
+       __attribute__((format(gnu_printf, fmt_idx, vargs_idx)))
+#endif
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+typedef __signed__ long long  __s64;
+typedef unsigned long long  __u64;
+typedef __u16 __le16;
+typedef __u16 __be16;
+typedef __u32 __le32;
+typedef __u32 __be32;
+typedef __u64 __le64;
+typedef __u64 __be64;
+
+#endif /* _WIN32 */
+
+#endif /* COMMON_WIN32_DEFS_H */
diff --git a/lib/utils.c b/lib/utils.c
index 8b5d6cb..036dd60 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -9,8 +9,6 @@ 
  * https://opensource.org/licenses/MIT.
  */
 
-#define _GNU_SOURCE /* for asprintf() and strerror_r() */
-
 #include "lib_private.h"
 
 #include <stdio.h>
@@ -53,6 +51,15 @@  libfsverity_set_error_callback(void (*cb)(const char *msg))
 	libfsverity_error_cb = cb;
 }
 
+#ifdef _WIN32
+static char *strerror_r(int errnum, char *buf, size_t buflen)
+{
+	strerror_s(buf, buflen, errnum);
+
+	return buf;
+}
+#endif
+
 void libfsverity_do_error_msg(const char *format, va_list va, int err)
 {
 	int saved_errno = errno;
diff --git a/programs/fsverity.c b/programs/fsverity.c
index 5d5fbe2..f68e034 100644
--- a/programs/fsverity.c
+++ b/programs/fsverity.c
@@ -28,6 +28,7 @@  static const struct fsverity_command {
 "    fsverity digest FILE...\n"
 "               [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n"
 "               [--compact] [--for-builtin-sig]\n"
+#ifndef _WIN32
 	}, {
 		.name = "enable",
 		.func = fsverity_cmd_enable,
@@ -43,6 +44,7 @@  static const struct fsverity_command {
 "Display the fs-verity digest of the given verity file(s)",
 		.usage_str =
 "    fsverity measure FILE...\n"
+#endif /* _WIN32 */
 	}, {
 		.name = "sign",
 		.func = fsverity_cmd_sign,
diff --git a/programs/utils.c b/programs/utils.c
index facccda..ce19b57 100644
--- a/programs/utils.c
+++ b/programs/utils.c
@@ -102,7 +102,7 @@  void install_libfsverity_error_handler(void)
 
 bool open_file(struct filedes *file, const char *filename, int flags, int mode)
 {
-	file->fd = open(filename, flags, mode);
+	file->fd = open(filename, flags | O_BINARY, mode);
 	if (file->fd < 0) {
 		error_msg_errno("can't open '%s' for %s", filename,
 				(flags & O_ACCMODE) == O_RDONLY ? "reading" :