Package: src:kmod
Version: 22-1.1
Severity: normal
Tags: patch

Please apply the following patch that adds support for detached
module signatures.  This is needed to support module signing
without sacrificing reproducibility or duplicating files.  It
has *not* been submitted upstream, but I can do that if you
prefer.  I have also not tested the gzip and xz cases.

Ben.

---
 libkmod/libkmod-file.c | 108 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 101 insertions(+), 7 deletions(-)

--- a/libkmod/libkmod-file.c
+++ b/libkmod/libkmod-file.c
@@ -52,6 +52,7 @@ struct kmod_file {
        gzFile gzf;
 #endif
        int fd;
+       int sig_fd;
        bool direct;
        off_t size;
        void *memory;
@@ -60,6 +61,37 @@ struct kmod_file {
        struct kmod_elf *elf;
 };
 
+static int append_detached_sig(struct kmod_file *file, size_t buf_size)
+{
+       struct stat st;
+       ssize_t read_size;
+
+       if (file->sig_fd < 0)
+               return 0;
+
+       if (fstat(file->sig_fd, &st) < 0)
+               return -errno;
+
+       /* Grow the buffer if necessary */
+       if ((size_t)st.st_size > buf_size - file->size) {
+               void *tmp = realloc(file->memory, file->size + st.st_size);
+               if (tmp == NULL)
+                       return -errno;
+               file->memory = tmp;
+       }
+
+       read_size = read(file->sig_fd, (char *)file->memory + file->size,
+                        st.st_size);
+       if (read_size < 0)
+               return -errno;
+       if (read_size != st.st_size)
+               return -EINVAL;
+
+       file->size += read_size;
+
+       return 0;
+}
+
 #ifdef ENABLE_XZ
 static void xz_uncompress_belch(struct kmod_file *file, lzma_ret ret)
 {
@@ -144,6 +176,7 @@ static int load_xz(struct kmod_file *fil
 {
        lzma_stream strm = LZMA_STREAM_INIT;
        lzma_ret lzret;
+       size_t buf_size;
        int ret;
 
        lzret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
@@ -155,7 +188,14 @@ static int load_xz(struct kmod_file *fil
                return -EINVAL;
        }
        ret = xz_uncompress(&strm, file);
+       buf_size = file->size + strm->avail_out;
        lzma_end(&strm);
+
+       if (!ret) {
+               ret = append_detached_sig(file, buf_size);
+               if (ret)
+                       free(file->memory);
+       }
        return ret;
 }
 
@@ -214,6 +254,11 @@ static int load_zlib(struct kmod_file *f
 
        file->memory = p;
        file->size = did;
+
+       err = append_detached_sig(file, total);
+       if (err)
+               goto error;
+
        p = NULL;
        return 0;
 
@@ -254,18 +299,50 @@ static int load_reg(struct kmod_file *fi
        if (fstat(file->fd, &st) < 0)
                return -errno;
 
-       file->size = st.st_size;
-       file->memory = mmap(NULL, file->size, PROT_READ, MAP_PRIVATE,
-                           file->fd, 0);
-       if (file->memory == MAP_FAILED)
-               return -errno;
-       file->direct = true;
+       if (file->sig_fd < 0) {
+               file->size = st.st_size;
+               file->memory = mmap(NULL, file->size, PROT_READ, MAP_PRIVATE,
+                                   file->fd, 0);
+               if (file->memory == MAP_FAILED)
+                       return -errno;
+               file->direct = true;
+       } else {
+               size_t plain_size = st.st_size, sig_size;
+               _cleanup_free_ unsigned char *p = NULL;
+               ssize_t ret;
+
+               if (fstat(file->sig_fd, &st) < 0)
+                       return -errno;
+               sig_size = st.st_size;
+
+               p = malloc(plain_size + sig_size);
+               if (!p)
+                       return -errno;
+
+               ret = read(file->fd, p, plain_size);
+               if (ret < 0)
+                       return -errno;
+               if ((size_t)ret != plain_size)
+                       return -EINVAL;
+               file->memory = p;
+               file->size = plain_size;
+
+               ret = append_detached_sig(file, plain_size + sig_size);
+               if (ret)
+                       return ret;
+
+               p = NULL;
+       }
+
        return 0;
 }
 
 static void unload_reg(struct kmod_file *file)
 {
-       munmap(file->memory, file->size);
+       if (file->direct)
+               munmap(file->memory, file->size);
+       else
+               free(file->memory);
 }
 
 static const struct file_ops reg_ops = {
@@ -285,6 +362,7 @@ struct kmod_file *kmod_file_open(const s
                                                const char *filename)
 {
        struct kmod_file *file = calloc(1, sizeof(struct kmod_file));
+       char *sig_filename = NULL;
        const struct comp_type *itr;
        size_t magic_size_max = 0;
        int err;
@@ -292,12 +370,25 @@ struct kmod_file *kmod_file_open(const s
        if (file == NULL)
                return NULL;
 
+       file->sig_fd = -1;
+
        file->fd = open(filename, O_RDONLY|O_CLOEXEC);
        if (file->fd < 0) {
                err = -errno;
                goto error;
        }
 
+       /* Try to open a detached signature.  If it's missing, that's OK. */
+       if (asprintf(&sig_filename, "%s.sig", filename) < 0) {
+               err = -errno;
+               goto error;
+       }
+       file->sig_fd = open(sig_filename, O_RDONLY|O_CLOEXEC);
+       if (file->sig_fd < 0 && errno != ENOENT) {
+               err = -errno;
+               goto error;
+       }
+
        for (itr = comp_types; itr->ops.load != NULL; itr++) {
                if (magic_size_max < itr->magic_size)
                        magic_size_max = itr->magic_size;
@@ -336,7 +427,10 @@ struct kmod_file *kmod_file_open(const s
        err = file->ops->load(file);
        file->ctx = ctx;
 error:
+       free(sig_filename);
        if (err < 0) {
+               if (file->sig_fd >= 0)
+                       close(file->sig_fd);
                if (file->fd >= 0)
                        close(file->fd);
                free(file);
@@ -373,6 +467,8 @@ void kmod_file_unref(struct kmod_file *f
                kmod_elf_unref(file->elf);
 
        file->ops->unload(file);
+       if (file->sig_fd >= 0)
+               close(file->sig_fd);
        if (file->fd >= 0)
                close(file->fd);
        free(file);

Attachment: signature.asc
Description: Digital signature

Reply via email to