1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

gpg: Detect already compressed data also when using a pipe.

* common/iobuf.c (file_filter_ctx_t): Add fields for the peek feature.
(file_filter): Implement peeking.
(iobuf_ioctl): Add new IOBUF_IOCTL_PEEK.
* common/iobuf.h (IOBUF_IOCTL_PEEK, IOBUFCTRL_PEEK): New.
* common/miscellaneous.c (is_file_compressed): Rewrite.  Detect PDF.
* g10/encrypt.c (encrypt_simple): Peek before detecting compression.
(encrypt_crypt): Ditto.
* g10/sign.c (sign_file): Also detect already compressed data.

* g10/options.h (opt): Add explicit_compress_option.
* g10/gpg.c (main): Set opt.explicit_compress_option for -z.

--

Note that this patch also introduces a compression check for signing
which was never done in the past.

GnuPG-bug-id: 6332
This commit is contained in:
Werner Koch 2023-01-18 18:04:50 +01:00
parent 94ae43be36
commit 60963d98cf
No known key found for this signature in database
GPG key ID: E3FDFF218E45B72B
9 changed files with 201 additions and 64 deletions

View file

@ -1,7 +1,7 @@
/* iobuf.c - File Handling for OpenPGP.
* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006, 2007, 2008,
* 2009, 2010, 2011 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
* Copyright (C) 2015, 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -95,6 +95,9 @@ typedef struct
int eof_seen;
int delayed_rc;
int print_only_name; /* Flags indicating that fname is not a real file. */
char peeked[32]; /* Read ahead buffer. */
byte npeeked; /* Number of bytes valid in peeked. */
byte upeeked; /* Number of bytes used from peeked. */
char fname[1]; /* Name of the file. */
} file_filter_ctx_t;
@ -458,7 +461,16 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
if (control == IOBUFCTRL_UNDERFLOW)
{
log_assert (size); /* We need a buffer. */
if (a->eof_seen)
if (a->npeeked > a->upeeked)
{
nbytes = a->npeeked - a->upeeked;
if (nbytes > size)
nbytes = size;
memcpy (buf, a->peeked + a->upeeked, nbytes);
a->upeeked += nbytes;
*ret_len = nbytes;
}
else if (a->eof_seen)
{
rc = -1;
*ret_len = 0;
@ -596,6 +608,73 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
a->delayed_rc = 0;
a->keep_open = 0;
a->no_cache = 0;
a->npeeked = 0;
a->upeeked = 0;
}
else if (control == IOBUFCTRL_PEEK)
{
/* Peek on the input. */
#ifdef HAVE_W32_SYSTEM
unsigned long nread;
nbytes = 0;
if (!ReadFile (f, a->peeked, sizeof a->peeked, &nread, NULL))
{
int ec = (int) GetLastError ();
if (ec != ERROR_BROKEN_PIPE)
{
rc = gpg_error_from_errno (ec);
log_error ("%s: read error: ec=%d\n", a->fname, ec);
}
a->npeeked = 0;
}
else if (!nread)
{
a->eof_seen = 1;
a->npeeked = 0;
}
else
{
a->npeeked = nread;
}
#else /* Unix */
int n;
peek_more:
do
{
n = read (f, a->peeked + a->npeeked, sizeof a->peeked - a->npeeked);
}
while (n == -1 && errno == EINTR);
if (n > 0)
{
a->npeeked += n;
if (a->npeeked < sizeof a->peeked)
goto peek_more;
}
else if (!n) /* eof */
{
if (a->npeeked)
a->delayed_rc = -1;
else
a->eof_seen = 1;
}
else /* error */
{
rc = gpg_error_from_syserror ();
if (gpg_err_code (rc) != GPG_ERR_EPIPE)
log_error ("%s: read error: %s\n", a->fname, gpg_strerror (rc));
if (a->npeeked)
a->delayed_rc = rc;
}
#endif /* Unix */
size = a->npeeked < size? a->npeeked : size;
memcpy (buf, a->peeked, size);
*ret_len = size;
rc = 0; /* Return success - the user needs to check ret_len. */
}
else if (control == IOBUFCTRL_DESC)
{
@ -1576,6 +1655,25 @@ iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
return fd_cache_synchronize (ptrval);
}
}
else if (cmd == IOBUF_IOCTL_PEEK)
{
/* Peek at a justed opened file. Use this only directly after a
* file has been opened for reading. Don't use it after you did
* a seek. This works only if just file filter has been
* pushed. Expects a buffer wit size INTVAL at PTRVAL and returns
* the number of bytes put into the buffer. */
if (DBG_IOBUF)
log_debug ("iobuf-%d.%d: ioctl '%s' peek\n",
a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a, desc));
if (a->filter == file_filter && ptrval && intval)
{
file_filter_ctx_t *fcx = a->filter_ov;
size_t len = intval;
if (!file_filter (fcx, IOBUFCTRL_PEEK, NULL, ptrval, &len))
return (int)len;
}
}
return -1;

View file

@ -106,6 +106,7 @@ enum
IOBUFCTRL_FLUSH = 4,
IOBUFCTRL_DESC = 5,
IOBUFCTRL_CANCEL = 6,
IOBUFCTRL_PEEK = 7,
IOBUFCTRL_USER = 16
};
@ -116,7 +117,8 @@ typedef enum
IOBUF_IOCTL_KEEP_OPEN = 1, /* Uses intval. */
IOBUF_IOCTL_INVALIDATE_CACHE = 2, /* Uses ptrval. */
IOBUF_IOCTL_NO_CACHE = 3, /* Uses intval. */
IOBUF_IOCTL_FSYNC = 4 /* Uses ptrval. */
IOBUF_IOCTL_FSYNC = 4, /* Uses ptrval. */
IOBUF_IOCTL_PEEK = 5 /* Uses intval and ptrval. */
} iobuf_ioctl_t;
enum iobuf_use

View file

@ -418,7 +418,7 @@ decode_c_string (const char *src)
/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
* packet. LEN should be at least 6. */
static int
is_openpgp_compressed_packet (unsigned char *buf, size_t len)
is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
{
int c, ctb, pkttype;
int lenbytes;
@ -460,63 +460,46 @@ is_openpgp_compressed_packet (unsigned char *buf, size_t len)
/*
* Check if the file is compressed.
* Check if the file is compressed. You need to pass the first bytes
* of the file as (BUF,BUFLEN). Returns true if the buffer seems to
* be compressed.
*/
int
is_file_compressed (const char *s, int *ret_rc)
is_file_compressed (const byte *buf, unsigned int buflen)
{
iobuf_t a;
byte buf[6];
int i;
int rc = 0;
int overflow;
int i;
struct magic_compress_s {
size_t len;
byte magic[4];
} magic[] = {
{ 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
{ 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
{ 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
};
struct magic_compress_s
{
byte len;
byte magic[5];
} magic[] =
{
{ 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
{ 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
{ 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
{ 5, { '%', 'P', 'D', 'F', '-'} } /* PDF */
};
if ( iobuf_is_pipe_filename (s) || !ret_rc )
return 0; /* We can't check stdin or no file was given */
a = iobuf_open( s );
if ( a == NULL ) {
*ret_rc = gpg_error_from_syserror ();
return 0;
}
iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
if ( iobuf_get_filelength( a, &overflow ) < 6 && !overflow) {
*ret_rc = 0;
goto leave;
if ( buflen < 6 )
{
return 0; /* Too short to check - assume uncompressed. */
}
if ( iobuf_read( a, buf, 6 ) == -1 ) {
*ret_rc = a->error;
goto leave;
}
for ( i = 0; i < DIM( magic ); i++ ) {
if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) {
*ret_rc = 0;
rc = 1;
goto leave;
for ( i = 0; i < DIM (magic); i++ )
{
if ( !memcmp( buf, magic[i].magic, magic[i].len ))
{
return 1; /* Is compressed. */
}
}
if (is_openpgp_compressed_packet (buf, 6))
{
*ret_rc = 0;
rc = 1;
}
if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
{
return 1; /* Already compressed. */
}
leave:
iobuf_close( a );
return rc;
return 0; /* Not detected as compressed. */
}

View file

@ -359,7 +359,7 @@ char *try_make_printable_string (const void *p, size_t n, int delim);
char *make_printable_string (const void *p, size_t n, int delim);
char *decode_c_string (const char *src);
int is_file_compressed (const char *s, int *ret_rc);
int is_file_compressed (const byte *buf, unsigned int buflen);
int match_multistr (const char *multistr,const char *match);