Compare commits
	
		
			No commits in common. "c8" and "a9-backports" have entirely different histories.
		
	
	
		
			c8
			...
			a9-backpor
		
	
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,2 +1,2 @@ | |||||||
| SOURCES/rsync-3.1.3.tar.gz | SOURCES/rsync-3.3.0.tar.gz | ||||||
| SOURCES/rsync-patches-3.1.3.tar.gz | SOURCES/rsync-patches-3.3.0.tar.gz | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| 82e7829c0b3cefbd33c233005341e2073c425629 SOURCES/rsync-3.1.3.tar.gz | 8e053bd4fb527b9032ee8f1691890540cfbbfa7c SOURCES/rsync-3.4.0.tar.gz | ||||||
| 74c16510a18ef43d797f9ceba6150f0862568cc0 SOURCES/rsync-patches-3.1.3.tar.gz | 816aa0585252b3d7603755c5d3d5b0c20e7267e2 SOURCES/rsync-patches-3.4.0.tar.gz | ||||||
|  | |||||||
| @ -1,22 +0,0 @@ | |||||||
| diff --git a/log.c b/log.c
 |  | ||||||
| index 34a013b..1aca728 100644
 |  | ||||||
| --- a/log.c
 |  | ||||||
| +++ b/log.c
 |  | ||||||
| @@ -377,10 +377,13 @@ output_msg:
 |  | ||||||
|  				filtered_fwrite(f, convbuf, outbuf.len, 0); |  | ||||||
|  				outbuf.len = 0; |  | ||||||
|  			} |  | ||||||
| -			if (!ierrno || ierrno == E2BIG)
 |  | ||||||
| -				continue;
 |  | ||||||
| -			fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
 |  | ||||||
| -			inbuf.len--;
 |  | ||||||
| +			/* Log one byte of illegal/incomplete sequence and continue with
 |  | ||||||
| +			 * the next character. Check that the buffer is non-empty for the
 |  | ||||||
| +			 * sake of robustness. */
 |  | ||||||
| +			if ((ierrno == EILSEQ || ierrno == EINVAL) && inbuf.len) {
 |  | ||||||
| +				fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
 |  | ||||||
| +				inbuf.len--;
 |  | ||||||
| +			}
 |  | ||||||
|  		} |  | ||||||
|  	} else |  | ||||||
|  #endif |  | ||||||
| @ -1,33 +0,0 @@ | |||||||
| diff --git a/sender.c b/sender.c
 |  | ||||||
| index 03e4aadd..9b432ed9 100644
 |  | ||||||
| --- a/sender.c
 |  | ||||||
| +++ b/sender.c
 |  | ||||||
| @@ -32,6 +32,7 @@ extern int logfile_format_has_i;
 |  | ||||||
|  extern int want_xattr_optim; |  | ||||||
|  extern int csum_length; |  | ||||||
|  extern int append_mode; |  | ||||||
| +extern int copy_links;
 |  | ||||||
|  extern int io_error; |  | ||||||
|  extern int flist_eof; |  | ||||||
|  extern int allowed_lull; |  | ||||||
| @@ -138,17 +139,16 @@ void successful_send(int ndx)
 |  | ||||||
|  		return; |  | ||||||
|  	f_name(file, fname); |  | ||||||
|   |  | ||||||
| -	if (do_lstat(fname, &st) < 0) {
 |  | ||||||
| +	if ((copy_links ? do_stat(fname, &st) : do_lstat(fname, &st)) < 0) {
 |  | ||||||
|  		failed_op = "re-lstat"; |  | ||||||
|  		goto failed; |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| -	if (S_ISREG(file->mode) /* Symlinks & devices don't need this check: */
 |  | ||||||
| -	 && (st.st_size != F_LENGTH(file) || st.st_mtime != file->modtime
 |  | ||||||
| +	if (st.st_size != F_LENGTH(file) || st.st_mtime != file->modtime
 |  | ||||||
|  #ifdef ST_MTIME_NSEC |  | ||||||
|  	 || (NSEC_BUMP(file) && (uint32)st.ST_MTIME_NSEC != F_MOD_NSEC(file)) |  | ||||||
|  #endif |  | ||||||
| -	)) {
 |  | ||||||
| +	) {
 |  | ||||||
|  		rprintf(FERROR_XFER, "ERROR: Skipping sender remove for changed file: %s\n", fname); |  | ||||||
|  		return; |  | ||||||
|  	} |  | ||||||
| @ -1,33 +0,0 @@ | |||||||
| diff --git a/io.c b/io.c
 |  | ||||||
| index 999c34e5..ceff3784 100644
 |  | ||||||
| --- a/io.c
 |  | ||||||
| +++ b/io.c
 |  | ||||||
| @@ -954,8 +954,17 @@ int send_msg(enum msgcode code, const char *buf, size_t len, int convert)
 |  | ||||||
|  	} else |  | ||||||
|  #endif |  | ||||||
|  		needed = len + 4 + 3; |  | ||||||
| -	if (iobuf.msg.len + needed > iobuf.msg.size)
 |  | ||||||
| -		perform_io(needed, PIO_NEED_MSGROOM);
 |  | ||||||
| +	if (iobuf.msg.len + needed > iobuf.msg.size) {
 |  | ||||||
| +		if (!am_receiver)
 |  | ||||||
| +			perform_io(needed, PIO_NEED_MSGROOM);
 |  | ||||||
| +		else { /* We allow the receiver to increase their iobuf.msg size to avoid a deadlock. */
 |  | ||||||
| +			size_t old_size = iobuf.msg.size;
 |  | ||||||
| +			restore_iobuf_size(&iobuf.msg);
 |  | ||||||
| +			realloc_xbuf(&iobuf.msg, iobuf.msg.size * 2);
 |  | ||||||
| +			if (iobuf.msg.pos + iobuf.msg.len > old_size)
 |  | ||||||
| +				memcpy(iobuf.msg.buf + old_size, iobuf.msg.buf, iobuf.msg.pos + iobuf.msg.len - old_size);
 |  | ||||||
| +		}
 |  | ||||||
| +	}
 |  | ||||||
|   |  | ||||||
|  	pos = iobuf.msg.pos + iobuf.msg.len; /* Must be set after any flushing. */ |  | ||||||
|  	if (pos >= iobuf.msg.size) |  | ||||||
| @@ -1176,7 +1185,7 @@ int read_line(int fd, char *buf, size_t bufsiz, int flags)
 |  | ||||||
|   |  | ||||||
|  #ifdef ICONV_OPTION |  | ||||||
|  	if (flags & RL_CONVERT && iconv_buf.size < bufsiz) |  | ||||||
| -		realloc_xbuf(&iconv_buf, bufsiz + 1024);
 |  | ||||||
| +		realloc_xbuf(&iconv_buf, ROUND_UP_1024(bufsiz) + 1024);
 |  | ||||||
|  #endif |  | ||||||
|   |  | ||||||
|    start: |  | ||||||
| @ -1,44 +0,0 @@ | |||||||
| commit bd17c2a4e237ca1f38544db65053ecfea6054009 |  | ||||||
| Author: Tomas Korbar <tkorbar@redhat.com> |  | ||||||
| Date:   Thu Sep 24 13:17:45 2020 +0200 |  | ||||||
| 
 |  | ||||||
|     Skip files for transfer that has been truncated during negotiation |  | ||||||
| 
 |  | ||||||
| diff --git a/rsync.1 b/rsync.1
 |  | ||||||
| index 6cabd44..855dd47 100644
 |  | ||||||
| --- a/rsync.1
 |  | ||||||
| +++ b/rsync.1
 |  | ||||||
| @@ -1004,8 +1004,10 @@ This causes rsync to update a file by appending data onto
 |  | ||||||
|  the end of the file, which presumes that the data that already exists on |  | ||||||
|  the receiving side is identical with the start of the file on the sending |  | ||||||
|  side.  If a file needs to be transferred and its size on the receiver is |  | ||||||
| -the same or longer than the size on the sender, the file is skipped.  This
 |  | ||||||
| -does not interfere with the updating of a file\(cq\&s non\-content attributes
 |  | ||||||
| +the same or longer than the size on the sender, the file is skipped. It
 |  | ||||||
| +also skips any files whose size on the sending side gets shorter during
 |  | ||||||
| +the send negotiations (rsync warns about a "diminished" file when this
 |  | ||||||
| +happens). This does not interfere with the updating of a file\(cq\&s non\-content attributes
 |  | ||||||
|  (e.g. permissions, ownership, etc.) when the file does not need to be |  | ||||||
|  transferred, nor does it affect the updating of any non\-regular files. |  | ||||||
|  Implies \fB\-\-inplace\fP. |  | ||||||
| diff --git a/sender.c b/sender.c
 |  | ||||||
| index 1cc28a1..e22eadd 100644
 |  | ||||||
| --- a/sender.c
 |  | ||||||
| +++ b/sender.c
 |  | ||||||
| @@ -379,6 +379,16 @@ void send_files(int f_in, int f_out)
 |  | ||||||
|  			} |  | ||||||
|  		} |  | ||||||
|   |  | ||||||
| +		if (append_mode > 0 && st.st_size < F_LENGTH(file)) {
 |  | ||||||
| +			rprintf(FWARNING, "skipped diminished file: %s\n",
 |  | ||||||
| +				full_fname(fname));
 |  | ||||||
| +			free_sums(s);
 |  | ||||||
| +			close(fd);
 |  | ||||||
| +			if (protocol_version >= 30)
 |  | ||||||
| +				send_msg_int(MSG_NO_SEND, ndx);
 |  | ||||||
| +			continue;
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
|  		if (st.st_size) { |  | ||||||
|  			int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE); |  | ||||||
|  			mbuf = map_file(fd, st.st_size, read_size, s->blength); |  | ||||||
| @ -1,57 +0,0 @@ | |||||||
| diff --git a/util.c b/util.c
 |  | ||||||
| index fbbfd8ba..235afa82 100644
 |  | ||||||
| --- a/util.c
 |  | ||||||
| +++ b/util.c
 |  | ||||||
| @@ -342,6 +342,7 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
 |  | ||||||
|  		if (robust_unlink(dest) && errno != ENOENT) { |  | ||||||
|  			int save_errno = errno; |  | ||||||
|  			rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest)); |  | ||||||
| +			close(ifd);
 |  | ||||||
|  			errno = save_errno; |  | ||||||
|  			return -1; |  | ||||||
|  		} |  | ||||||
| diff --git a/lib/pool_alloc.c b/lib/pool_alloc.c
 |  | ||||||
| index 5856d591..a70a3f1a 100644
 |  | ||||||
| --- a/lib/pool_alloc.c
 |  | ||||||
| +++ b/lib/pool_alloc.c
 |  | ||||||
| @@ -49,15 +49,15 @@ pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
 |  | ||||||
|  { |  | ||||||
|  	struct alloc_pool *pool; |  | ||||||
|   |  | ||||||
| -	if (!(pool = new0(struct alloc_pool)))
 |  | ||||||
| -		return NULL;
 |  | ||||||
| -
 |  | ||||||
|  	if ((MINALIGN & (MINALIGN - 1)) != 0) { |  | ||||||
|  		if (bomb) |  | ||||||
|  			(*bomb)("Compiler error: MINALIGN is not a power of 2\n"); |  | ||||||
|  		return NULL; |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| +	if (!(pool = new0(struct alloc_pool)))
 |  | ||||||
| +		return NULL;
 |  | ||||||
| +
 |  | ||||||
|  	if (!size) |  | ||||||
|  		size = POOL_DEF_EXTENT; |  | ||||||
|  	if (!quantum) |  | ||||||
| diff --git a/batch.c b/batch.c
 |  | ||||||
| index 21c632fc..1ab66e90 100644
 |  | ||||||
| --- a/batch.c
 |  | ||||||
| +++ b/batch.c
 |  | ||||||
| @@ -216,7 +216,7 @@ static void write_filter_rules(int fd)
 |  | ||||||
|  void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt) |  | ||||||
|  { |  | ||||||
|  	int fd, i, len, err = 0; |  | ||||||
| -	char *p, filename[MAXPATHLEN];
 |  | ||||||
| +	char *p, *p2, filename[MAXPATHLEN];
 |  | ||||||
|   |  | ||||||
|  	stringjoin(filename, sizeof filename, |  | ||||||
|  		   batch_name, ".sh", NULL); |  | ||||||
| @@ -267,7 +267,7 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
 |  | ||||||
|  				err = 1; |  | ||||||
|  		} |  | ||||||
|  	} |  | ||||||
| -	if (!(p = check_for_hostspec(argv[argc - 1], &p, &i)))
 |  | ||||||
| +	if (!(p = check_for_hostspec(argv[argc - 1], &p2, &i)))
 |  | ||||||
|  		p = argv[argc - 1]; |  | ||||||
|  	if (write(fd, " ${1:-", 6) != 6 |  | ||||||
|  	 || write_arg(fd, p) < 0) |  | ||||||
| @ -1,343 +0,0 @@ | |||||||
| From 5c44459c3b28a9bd3283aaceab7c615f8020c531 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Mark Adler <madler@alumni.caltech.edu> |  | ||||||
| Date: Tue, 17 Apr 2018 22:09:22 -0700 |  | ||||||
| Subject: [PATCH] Fix a bug that can crash deflate on some input when using |  | ||||||
|  Z_FIXED. |  | ||||||
| 
 |  | ||||||
| This bug was reported by Danilo Ramos of Eideticom, Inc. It has |  | ||||||
| lain in wait 13 years before being found! The bug was introduced |  | ||||||
| in zlib 1.2.2.2, with the addition of the Z_FIXED option. That |  | ||||||
| option forces the use of fixed Huffman codes. For rare inputs with |  | ||||||
| a large number of distant matches, the pending buffer into which |  | ||||||
| the compressed data is written can overwrite the distance symbol |  | ||||||
| table which it overlays. That results in corrupted output due to |  | ||||||
| invalid distances, and can result in out-of-bound accesses, |  | ||||||
| crashing the application. |  | ||||||
| 
 |  | ||||||
| The fix here combines the distance buffer and literal/length |  | ||||||
| buffers into a single symbol buffer. Now three bytes of pending |  | ||||||
| buffer space are opened up for each literal or length/distance |  | ||||||
| pair consumed, instead of the previous two bytes. This assures |  | ||||||
| that the pending buffer cannot overwrite the symbol table, since |  | ||||||
| the maximum fixed code compressed length/distance is 31 bits, and |  | ||||||
| since there are four bytes of pending space for every three bytes |  | ||||||
| of symbol space. |  | ||||||
| ---
 |  | ||||||
|  deflate.c | 74 ++++++++++++++++++++++++++++++++++++++++--------------- |  | ||||||
|  deflate.h | 25 +++++++++---------- |  | ||||||
|  trees.c   | 50 +++++++++++-------------------------- |  | ||||||
|  3 files changed, 79 insertions(+), 70 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/zlib/deflate.c b/zlib/deflate.c
 |  | ||||||
| index 425babc00..19cba873a 100644
 |  | ||||||
| --- a/zlib/deflate.c
 |  | ||||||
| +++ b/zlib/deflate.c
 |  | ||||||
| @@ -255,11 +255,6 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
 |  | ||||||
|      int wrap = 1; |  | ||||||
|      static const char my_version[] = ZLIB_VERSION; |  | ||||||
|   |  | ||||||
| -    ushf *overlay;
 |  | ||||||
| -    /* We overlay pending_buf and d_buf+l_buf. This works since the average
 |  | ||||||
| -     * output size for (length,distance) codes is <= 24 bits.
 |  | ||||||
| -     */
 |  | ||||||
| -
 |  | ||||||
|      if (version == Z_NULL || version[0] != my_version[0] || |  | ||||||
|          stream_size != sizeof(z_stream)) { |  | ||||||
|          return Z_VERSION_ERROR; |  | ||||||
| @@ -329,9 +324,47 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
 |  | ||||||
|   |  | ||||||
|      s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ |  | ||||||
|   |  | ||||||
| -    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
 |  | ||||||
| -    s->pending_buf = (uchf *) overlay;
 |  | ||||||
| -    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
 |  | ||||||
| +    /* We overlay pending_buf and sym_buf. This works since the average size
 |  | ||||||
| +     * for length/distance pairs over any compressed block is assured to be 31
 |  | ||||||
| +     * bits or less.
 |  | ||||||
| +     *
 |  | ||||||
| +     * Analysis: The longest fixed codes are a length code of 8 bits plus 5
 |  | ||||||
| +     * extra bits, for lengths 131 to 257. The longest fixed distance codes are
 |  | ||||||
| +     * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest
 |  | ||||||
| +     * possible fixed-codes length/distance pair is then 31 bits total.
 |  | ||||||
| +     *
 |  | ||||||
| +     * sym_buf starts one-fourth of the way into pending_buf. So there are
 |  | ||||||
| +     * three bytes in sym_buf for every four bytes in pending_buf. Each symbol
 |  | ||||||
| +     * in sym_buf is three bytes -- two for the distance and one for the
 |  | ||||||
| +     * literal/length. As each symbol is consumed, the pointer to the next
 |  | ||||||
| +     * sym_buf value to read moves forward three bytes. From that symbol, up to
 |  | ||||||
| +     * 31 bits are written to pending_buf. The closest the written pending_buf
 |  | ||||||
| +     * bits gets to the next sym_buf symbol to read is just before the last
 |  | ||||||
| +     * code is written. At that time, 31*(n-2) bits have been written, just
 |  | ||||||
| +     * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at
 |  | ||||||
| +     * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1
 |  | ||||||
| +     * symbols are written.) The closest the writing gets to what is unread is
 |  | ||||||
| +     * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and
 |  | ||||||
| +     * can range from 128 to 32768.
 |  | ||||||
| +     *
 |  | ||||||
| +     * Therefore, at a minimum, there are 142 bits of space between what is
 |  | ||||||
| +     * written and what is read in the overlain buffers, so the symbols cannot
 |  | ||||||
| +     * be overwritten by the compressed data. That space is actually 139 bits,
 |  | ||||||
| +     * due to the three-bit fixed-code block header.
 |  | ||||||
| +     *
 |  | ||||||
| +     * That covers the case where either Z_FIXED is specified, forcing fixed
 |  | ||||||
| +     * codes, or when the use of fixed codes is chosen, because that choice
 |  | ||||||
| +     * results in a smaller compressed block than dynamic codes. That latter
 |  | ||||||
| +     * condition then assures that the above analysis also covers all dynamic
 |  | ||||||
| +     * blocks. A dynamic-code block will only be chosen to be emitted if it has
 |  | ||||||
| +     * fewer bits than a fixed-code block would for the same set of symbols.
 |  | ||||||
| +     * Therefore its average symbol length is assured to be less than 31. So
 |  | ||||||
| +     * the compressed data for a dynamic block also cannot overwrite the
 |  | ||||||
| +     * symbols from which it is being constructed.
 |  | ||||||
| +     */
 |  | ||||||
| +
 |  | ||||||
| +    s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4);
 |  | ||||||
| +    s->pending_buf_size = (ulg)s->lit_bufsize * 4;
 |  | ||||||
|   |  | ||||||
|      if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || |  | ||||||
|          s->pending_buf == Z_NULL) { |  | ||||||
| @@ -340,8 +373,12 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
 |  | ||||||
|          deflateEnd (strm); |  | ||||||
|          return Z_MEM_ERROR; |  | ||||||
|      } |  | ||||||
| -    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
 |  | ||||||
| -    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
 |  | ||||||
| +    s->sym_buf = s->pending_buf + s->lit_bufsize;
 |  | ||||||
| +    s->sym_end = (s->lit_bufsize - 1) * 3;
 |  | ||||||
| +    /* We avoid equality with lit_bufsize*3 because of wraparound at 64K
 |  | ||||||
| +     * on 16 bit machines and because stored blocks are restricted to
 |  | ||||||
| +     * 64K-1 bytes.
 |  | ||||||
| +     */
 |  | ||||||
|   |  | ||||||
|      s->level = level; |  | ||||||
|      s->strategy = strategy; |  | ||||||
| @@ -552,7 +589,7 @@ int ZEXPORT deflatePrime (strm, bits, value)
 |  | ||||||
|   |  | ||||||
|      if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; |  | ||||||
|      s = strm->state; |  | ||||||
| -    if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
 |  | ||||||
| +    if (s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
 |  | ||||||
|          return Z_BUF_ERROR; |  | ||||||
|      do { |  | ||||||
|          put = Buf_size - s->bi_valid; |  | ||||||
| @@ -1113,7 +1150,6 @@ int ZEXPORT deflateCopy (dest, source)
 |  | ||||||
|  #else |  | ||||||
|      deflate_state *ds; |  | ||||||
|      deflate_state *ss; |  | ||||||
| -    ushf *overlay;
 |  | ||||||
|   |  | ||||||
|   |  | ||||||
|      if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { |  | ||||||
| @@ -1133,8 +1169,7 @@ int ZEXPORT deflateCopy (dest, source)
 |  | ||||||
|      ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); |  | ||||||
|      ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos)); |  | ||||||
|      ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos)); |  | ||||||
| -    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
 |  | ||||||
| -    ds->pending_buf = (uchf *) overlay;
 |  | ||||||
| +    ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4);
 |  | ||||||
|   |  | ||||||
|      if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || |  | ||||||
|          ds->pending_buf == Z_NULL) { |  | ||||||
| @@ -1148,8 +1183,7 @@ int ZEXPORT deflateCopy (dest, source)
 |  | ||||||
|      zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); |  | ||||||
|   |  | ||||||
|      ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); |  | ||||||
| -    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
 |  | ||||||
| -    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
 |  | ||||||
| +    ds->sym_buf = ds->pending_buf + ds->lit_bufsize;
 |  | ||||||
|   |  | ||||||
|      ds->l_desc.dyn_tree = ds->dyn_ltree; |  | ||||||
|      ds->d_desc.dyn_tree = ds->dyn_dtree; |  | ||||||
| @@ -1771,7 +1771,7 @@ local block_state deflate_fast(s, flush)
 |  | ||||||
|          FLUSH_BLOCK(s, 1); |  | ||||||
|          return finish_done; |  | ||||||
|      } |  | ||||||
| -    if (s->last_lit)
 |  | ||||||
| +    if (s->sym_next)
 |  | ||||||
|          FLUSH_BLOCK(s, 0); |  | ||||||
|      return block_done; |  | ||||||
|  } |  | ||||||
| @@ -1912,7 +1912,7 @@ local block_state deflate_slow(s, flush)
 |  | ||||||
|          FLUSH_BLOCK(s, 1); |  | ||||||
|          return finish_done; |  | ||||||
|      } |  | ||||||
| -    if (s->last_lit)
 |  | ||||||
| +    if (s->sym_next)
 |  | ||||||
|          FLUSH_BLOCK(s, 0); |  | ||||||
|      return block_done; |  | ||||||
|  } |  | ||||||
| @@ -1987,7 +1987,7 @@ local block_state deflate_rle(s, flush)
 |  | ||||||
|          FLUSH_BLOCK(s, 1); |  | ||||||
|          return finish_done; |  | ||||||
|      } |  | ||||||
| -    if (s->last_lit)
 |  | ||||||
| +    if (s->sym_next)
 |  | ||||||
|          FLUSH_BLOCK(s, 0); |  | ||||||
|      return block_done; |  | ||||||
|  } |  | ||||||
| @@ -2026,7 +2026,7 @@ local block_state deflate_huff(s, flush)
 |  | ||||||
|          FLUSH_BLOCK(s, 1); |  | ||||||
|          return finish_done; |  | ||||||
|      } |  | ||||||
| -    if (s->last_lit)
 |  | ||||||
| +    if (s->sym_next)
 |  | ||||||
|          FLUSH_BLOCK(s, 0); |  | ||||||
|      return block_done; |  | ||||||
|  } |  | ||||||
| diff --git a/zlib/deflate.h b/zlib/deflate.h
 |  | ||||||
| index 23ecdd312..d4cf1a98b 100644
 |  | ||||||
| --- a/zlib/deflate.h
 |  | ||||||
| +++ b/zlib/deflate.h
 |  | ||||||
| @@ -217,7 +217,7 @@ typedef struct internal_state {
 |  | ||||||
|      /* Depth of each subtree used as tie breaker for trees of equal frequency |  | ||||||
|       */ |  | ||||||
|   |  | ||||||
| -    uchf *l_buf;          /* buffer for literals or lengths */
 |  | ||||||
| +    uchf *sym_buf;        /* buffer for distances and literals/lengths */
 |  | ||||||
|   |  | ||||||
|      uInt  lit_bufsize; |  | ||||||
|      /* Size of match buffer for literals/lengths.  There are 4 reasons for |  | ||||||
| @@ -239,13 +239,8 @@ typedef struct internal_state {
 |  | ||||||
|       *   - I can't count above 4 |  | ||||||
|       */ |  | ||||||
|   |  | ||||||
| -    uInt last_lit;      /* running index in l_buf */
 |  | ||||||
| -
 |  | ||||||
| -    ushf *d_buf;
 |  | ||||||
| -    /* Buffer for distances. To simplify the code, d_buf and l_buf have
 |  | ||||||
| -     * the same number of elements. To use different lengths, an extra flag
 |  | ||||||
| -     * array would be necessary.
 |  | ||||||
| -     */
 |  | ||||||
| +    uInt sym_next;      /* running index in sym_buf */
 |  | ||||||
| +    uInt sym_end;       /* symbol table full when sym_next reaches this */
 |  | ||||||
|   |  | ||||||
|      ulg opt_len;        /* bit length of current block with optimal trees */ |  | ||||||
|      ulg static_len;     /* bit length of current block with static trees */ |  | ||||||
| @@ -317,20 +317,22 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
 |  | ||||||
|   |  | ||||||
|  # define _tr_tally_lit(s, c, flush) \ |  | ||||||
|    { uch cc = (c); \ |  | ||||||
| -    s->d_buf[s->last_lit] = 0; \
 |  | ||||||
| -    s->l_buf[s->last_lit++] = cc; \
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = 0; \
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = 0; \
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = cc; \
 |  | ||||||
|      s->dyn_ltree[cc].Freq++; \ |  | ||||||
| -    flush = (s->last_lit == s->lit_bufsize-1); \
 |  | ||||||
| +    flush = (s->sym_next == s->sym_end); \
 |  | ||||||
|     } |  | ||||||
|  # define _tr_tally_dist(s, distance, length, flush) \ |  | ||||||
|    { uch len = (length); \ |  | ||||||
|      ush dist = (distance); \ |  | ||||||
| -    s->d_buf[s->last_lit] = dist; \
 |  | ||||||
| -    s->l_buf[s->last_lit++] = len; \
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = dist; \
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = dist >> 8; \
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = len; \
 |  | ||||||
|      dist--; \ |  | ||||||
|      s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ |  | ||||||
|      s->dyn_dtree[d_code(dist)].Freq++; \ |  | ||||||
| -    flush = (s->last_lit == s->lit_bufsize-1); \
 |  | ||||||
| +    flush = (s->sym_next == s->sym_end); \
 |  | ||||||
|    } |  | ||||||
|  #else |  | ||||||
|  # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) |  | ||||||
| diff --git a/zlib/trees.c b/zlib/trees.c
 |  | ||||||
| index 4f4a65011..decaeb7c3 100644
 |  | ||||||
| --- a/zlib/trees.c
 |  | ||||||
| +++ b/zlib/trees.c
 |  | ||||||
| @@ -416,7 +416,7 @@ local void init_block(s)
 |  | ||||||
|   |  | ||||||
|      s->dyn_ltree[END_BLOCK].Freq = 1; |  | ||||||
|      s->opt_len = s->static_len = 0L; |  | ||||||
| -    s->last_lit = s->matches = 0;
 |  | ||||||
| +    s->sym_next = s->matches = 0;
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  #define SMALLEST 1 |  | ||||||
| @@ -948,7 +948,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
 |  | ||||||
|   |  | ||||||
|          Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", |  | ||||||
|                  opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, |  | ||||||
| -                s->last_lit));
 |  | ||||||
| +                s->sym_next / 3));
 |  | ||||||
|   |  | ||||||
|          if (static_lenb <= opt_lenb) opt_lenb = static_lenb; |  | ||||||
|   |  | ||||||
| @@ -1017,8 +1017,9 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
 |  | ||||||
|      unsigned dist;  /* distance of matched string */ |  | ||||||
|      unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */ |  | ||||||
|  { |  | ||||||
| -    s->d_buf[s->last_lit] = (ush)dist;
 |  | ||||||
| -    s->l_buf[s->last_lit++] = (uch)lc;
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = dist;
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = dist >> 8;
 |  | ||||||
| +    s->sym_buf[s->sym_next++] = lc;
 |  | ||||||
|      if (dist == 0) { |  | ||||||
|          /* lc is the unmatched char */ |  | ||||||
|          s->dyn_ltree[lc].Freq++; |  | ||||||
| @@ -1033,30 +1034,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
 |  | ||||||
|          s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; |  | ||||||
|          s->dyn_dtree[d_code(dist)].Freq++; |  | ||||||
|      } |  | ||||||
| -
 |  | ||||||
| -#ifdef TRUNCATE_BLOCK
 |  | ||||||
| -    /* Try to guess if it is profitable to stop the current block here */
 |  | ||||||
| -    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
 |  | ||||||
| -        /* Compute an upper bound for the compressed length */
 |  | ||||||
| -        ulg out_length = (ulg)s->last_lit*8L;
 |  | ||||||
| -        ulg in_length = (ulg)((long)s->strstart - s->block_start);
 |  | ||||||
| -        int dcode;
 |  | ||||||
| -        for (dcode = 0; dcode < D_CODES; dcode++) {
 |  | ||||||
| -            out_length += (ulg)s->dyn_dtree[dcode].Freq *
 |  | ||||||
| -                (5L+extra_dbits[dcode]);
 |  | ||||||
| -        }
 |  | ||||||
| -        out_length >>= 3;
 |  | ||||||
| -        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
 |  | ||||||
| -               s->last_lit, in_length, out_length,
 |  | ||||||
| -               100L - out_length*100L/in_length));
 |  | ||||||
| -        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
 |  | ||||||
| -    }
 |  | ||||||
| -#endif
 |  | ||||||
| -    return (s->last_lit == s->lit_bufsize-1);
 |  | ||||||
| -    /* We avoid equality with lit_bufsize because of wraparound at 64K
 |  | ||||||
| -     * on 16 bit machines and because stored blocks are restricted to
 |  | ||||||
| -     * 64K-1 bytes.
 |  | ||||||
| -     */
 |  | ||||||
| +    return (s->sym_next == s->sym_end);
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  /* =========================================================================== |  | ||||||
| @@ -1069,13 +1047,14 @@ local void compress_block(s, ltree, dtree)
 |  | ||||||
|  { |  | ||||||
|      unsigned dist;      /* distance of matched string */ |  | ||||||
|      int lc;             /* match length or unmatched char (if dist == 0) */ |  | ||||||
| -    unsigned lx = 0;    /* running index in l_buf */
 |  | ||||||
| +    unsigned sx = 0;    /* running index in sym_buf */
 |  | ||||||
|      unsigned code;      /* the code to send */ |  | ||||||
|      int extra;          /* number of extra bits to send */ |  | ||||||
|   |  | ||||||
| -    if (s->last_lit != 0) do {
 |  | ||||||
| -        dist = s->d_buf[lx];
 |  | ||||||
| -        lc = s->l_buf[lx++];
 |  | ||||||
| +    if (s->sym_next != 0) do {
 |  | ||||||
| +        dist = s->sym_buf[sx++] & 0xff;
 |  | ||||||
| +        dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
 |  | ||||||
| +        lc = s->sym_buf[sx++];
 |  | ||||||
|          if (dist == 0) { |  | ||||||
|              send_code(s, lc, ltree); /* send a literal byte */ |  | ||||||
|              Tracecv(isgraph(lc), (stderr," '%c' ", lc)); |  | ||||||
| @@ -1100,11 +1079,10 @@ local void compress_block(s, ltree, dtree)
 |  | ||||||
|              } |  | ||||||
|          } /* literal or match pair ? */ |  | ||||||
|   |  | ||||||
| -        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
 |  | ||||||
| -        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
 |  | ||||||
| -               "pendingBuf overflow");
 |  | ||||||
| +        /* Check that the overlay between pending_buf and sym_buf is ok: */
 |  | ||||||
| +        Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
 |  | ||||||
|   |  | ||||||
| -    } while (lx < s->last_lit);
 |  | ||||||
| +    } while (sx < s->sym_next);
 |  | ||||||
|   |  | ||||||
|      send_code(s, END_BLOCK, ltree); |  | ||||||
|  } |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,16 +0,0 @@ | |||||||
| diff --git a/zlib/inflate.c b/zlib/inflate.c
 |  | ||||||
| index e43abd9..bd33c19 100644
 |  | ||||||
| --- a/zlib/inflate.c
 |  | ||||||
| +++ b/zlib/inflate.c
 |  | ||||||
| @@ -740,8 +740,9 @@ int flush;
 |  | ||||||
|                  if (copy > have) copy = have; |  | ||||||
|                  if (copy) { |  | ||||||
|                      if (state->head != Z_NULL && |  | ||||||
| -                        state->head->extra != Z_NULL) {
 |  | ||||||
| -                        len = state->head->extra_len - state->length;
 |  | ||||||
| +                        state->head->extra != Z_NULL &&
 |  | ||||||
| +                        (len = state->head->extra_len - state->length) <
 |  | ||||||
| +			    state->head->extra_max) {
 |  | ||||||
|                          zmemcpy(state->head->extra + len, next, |  | ||||||
|                                  len + copy > state->head->extra_max ? |  | ||||||
|                                  state->head->extra_max - len : copy); |  | ||||||
| @ -1,14 +0,0 @@ | |||||||
| diff --git a/match.c b/match.c
 |  | ||||||
| index 36e78ed..dfd6af2 100644
 |  | ||||||
| --- a/match.c
 |  | ||||||
| +++ b/match.c
 |  | ||||||
| @@ -147,6 +147,9 @@ static void hash_search(int f,struct sum_struct *s,
 |  | ||||||
|  	int more; |  | ||||||
|  	schar *map; |  | ||||||
|   |  | ||||||
| +	// prevent possible memory leaks
 |  | ||||||
| +	memset(sum2, 0, sizeof sum2);
 |  | ||||||
| +
 |  | ||||||
|  	/* want_i is used to encourage adjacent matches, allowing the RLL |  | ||||||
|  	 * coding of the output to work more efficiently. */ |  | ||||||
|  	want_i = 0; |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| diff --git a/flist.c b/flist.c
 |  | ||||||
| index 464d556..087f9da 100644
 |  | ||||||
| --- a/flist.c
 |  | ||||||
| +++ b/flist.c
 |  | ||||||
| @@ -2584,6 +2584,19 @@ struct file_list *recv_file_list(int f, int dir_ndx)
 |  | ||||||
|  		init_hard_links(); |  | ||||||
|  #endif |  | ||||||
|   |  | ||||||
| +	if (inc_recurse && dir_ndx >= 0) {
 |  | ||||||
| +		if (dir_ndx >= dir_flist->used) {
 |  | ||||||
| +			rprintf(FERROR_XFER, "rsync: refusing invalid dir_ndx %u >= %u\n", dir_ndx, dir_flist->used);
 |  | ||||||
| +			exit_cleanup(RERR_PROTOCOL);
 |  | ||||||
| +		}
 |  | ||||||
| +		struct file_struct *file = dir_flist->files[dir_ndx];
 |  | ||||||
| +		if (file->flags & FLAG_GOT_DIR_FLIST) {
 |  | ||||||
| +			rprintf(FERROR_XFER, "rsync: refusing malicious duplicate flist for dir %d\n", dir_ndx);
 |  | ||||||
| +			exit_cleanup(RERR_PROTOCOL);
 |  | ||||||
| +		}
 |  | ||||||
| +		file->flags |= FLAG_GOT_DIR_FLIST;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
|  	flist = flist_new(0, "recv_file_list"); |  | ||||||
|   |  | ||||||
|  	if (inc_recurse) { |  | ||||||
| diff --git a/rsync.h b/rsync.h
 |  | ||||||
| index b357dad..bc9abac 100644
 |  | ||||||
| --- a/rsync.h
 |  | ||||||
| +++ b/rsync.h
 |  | ||||||
| @@ -83,6 +83,7 @@
 |  | ||||||
|  #define FLAG_SKIP_GROUP (1<<10)	/* receiver/generator */ |  | ||||||
|  #define FLAG_TIME_FAILED (1<<11)/* generator */ |  | ||||||
|  #define FLAG_MOD_NSEC (1<<12)	/* sender/receiver/generator */ |  | ||||||
| +#define FLAG_GOT_DIR_FLIST (1<<13)/* sender/receiver/generator - dir_flist only */
 |  | ||||||
|   |  | ||||||
|  /* These flags are passed to functions but not stored. */ |  | ||||||
|   |  | ||||||
| @ -1,57 +0,0 @@ | |||||||
| diff --git a/testsuite/unsafe-byname.test b/testsuite/unsafe-byname.test
 |  | ||||||
| index 75e7201..d2e318e 100644
 |  | ||||||
| --- a/testsuite/unsafe-byname.test
 |  | ||||||
| +++ b/testsuite/unsafe-byname.test
 |  | ||||||
| @@ -40,7 +40,7 @@ test_unsafe ..//../dest 		from/dir			unsafe
 |  | ||||||
|  test_unsafe ..				from/file			safe |  | ||||||
|  test_unsafe ../..			from/file			unsafe |  | ||||||
|  test_unsafe ..//..			from//file			unsafe |  | ||||||
| -test_unsafe dir/..			from				safe
 |  | ||||||
| +test_unsafe dir/..			from				unsafe
 |  | ||||||
|  test_unsafe dir/../..			from				unsafe |  | ||||||
|  test_unsafe dir/..//..			from				unsafe |  | ||||||
|   |  | ||||||
| diff --git a/util.c b/util.c
 |  | ||||||
| index da50ff1..f260d39 100644
 |  | ||||||
| --- a/util.c
 |  | ||||||
| +++ b/util.c
 |  | ||||||
| @@ -1318,7 +1318,14 @@ int handle_partial_dir(const char *fname, int create)
 |  | ||||||
|   * |  | ||||||
|   * "src" is the top source directory currently applicable at the level |  | ||||||
|   * of the referenced symlink.  This is usually the symlink's full path |  | ||||||
| - * (including its name), as referenced from the root of the transfer. */
 |  | ||||||
| + * (including its name), as referenced from the root of the transfer.
 |  | ||||||
| + *
 |  | ||||||
| + * NOTE: this also rejects dest names with a .. component in other
 |  | ||||||
| + * than the first component of the name ie. it rejects names such as
 |  | ||||||
| + * a/b/../x/y. This needs to be done as the leading subpaths 'a' or
 |  | ||||||
| + * 'b' could later be replaced with symlinks such as a link to '.'
 |  | ||||||
| + * resulting in the link being transferred now becoming unsafe
 |  | ||||||
| + */
 |  | ||||||
|  int unsafe_symlink(const char *dest, const char *src) |  | ||||||
|  { |  | ||||||
|  	const char *name, *slash; |  | ||||||
| @@ -1328,6 +1335,23 @@ int unsafe_symlink(const char *dest, const char *src)
 |  | ||||||
|  	if (!dest || !*dest || *dest == '/') |  | ||||||
|  		return 1; |  | ||||||
|   |  | ||||||
| +	// reject destinations with /../ in the name other than at the start of the name
 |  | ||||||
| +	const char *dest2 = dest;
 |  | ||||||
| +	while (strncmp(dest2, "../", 3) == 0) {
 |  | ||||||
| +	    dest2 += 3;
 |  | ||||||
| +	    while (*dest2 == '/') {
 |  | ||||||
| +		// allow for ..//..///../foo
 |  | ||||||
| +		dest2++;
 |  | ||||||
| +	    }
 |  | ||||||
| +	}
 |  | ||||||
| +	if (strstr(dest2, "/../"))
 |  | ||||||
| +	    return 1;
 |  | ||||||
| +
 |  | ||||||
| +	// reject if the destination ends in /..
 |  | ||||||
| +	const size_t dlen = strlen(dest);
 |  | ||||||
| +	if (dlen > 3 && strcmp(&dest[dlen-3], "/..") == 0)
 |  | ||||||
| +	    return 1;
 |  | ||||||
| +
 |  | ||||||
|  	/* find out what our safety margin is */ |  | ||||||
|  	for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) { |  | ||||||
|  		/* ".." segment starts the count over.  "." segment is ignored. */ |  | ||||||
| @ -1,141 +0,0 @@ | |||||||
| diff --git a/checksum.c b/checksum.c
 |  | ||||||
| index cb21882..66e8089 100644
 |  | ||||||
| --- a/checksum.c
 |  | ||||||
| +++ b/checksum.c
 |  | ||||||
| @@ -406,7 +406,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
 |  | ||||||
|   |  | ||||||
|  	memset(sum, 0, MAX_DIGEST_LEN); |  | ||||||
|   |  | ||||||
| -	fd = do_open(fname, O_RDONLY, 0);
 |  | ||||||
| +	fd = do_open_checklinks(fname);
 |  | ||||||
|  	if (fd == -1) |  | ||||||
|  		return; |  | ||||||
|   |  | ||||||
| diff --git a/generator.c b/generator.c
 |  | ||||||
| index 110db28..3f13bb9 100644
 |  | ||||||
| --- a/generator.c
 |  | ||||||
| +++ b/generator.c
 |  | ||||||
| @@ -1867,7 +1867,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
|  	/* open the file */ |  | ||||||
| -	if ((fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
 |  | ||||||
| +	if ((fd = do_open_checklinks(fnamecmp)) < 0) {
 |  | ||||||
|  		rsyserr(FERROR, errno, "failed to open %s, continuing", |  | ||||||
|  			full_fname(fnamecmp)); |  | ||||||
|  	  pretend_missing: |  | ||||||
| diff --git a/receiver.c b/receiver.c
 |  | ||||||
| index 8031b8f..edfbb21 100644
 |  | ||||||
| --- a/receiver.c
 |  | ||||||
| +++ b/receiver.c
 |  | ||||||
| @@ -775,7 +775,7 @@ int recv_files(int f_in, int f_out, char *local_name)
 |  | ||||||
|  		if (fd1 == -1 && protocol_version < 29) { |  | ||||||
|  			if (fnamecmp != fname) { |  | ||||||
|  				fnamecmp = fname; |  | ||||||
| -				fd1 = do_open(fnamecmp, O_RDONLY, 0);
 |  | ||||||
| +				fd1 = do_open_nofollow(fnamecmp, O_RDONLY);
 |  | ||||||
|  			} |  | ||||||
|   |  | ||||||
|  			if (fd1 == -1 && basis_dir[0]) { |  | ||||||
| diff --git a/sender.c b/sender.c
 |  | ||||||
| index 2bbff2f..a4d46c3 100644
 |  | ||||||
| --- a/sender.c
 |  | ||||||
| +++ b/sender.c
 |  | ||||||
| @@ -350,7 +350,7 @@ void send_files(int f_in, int f_out)
 |  | ||||||
|  			exit_cleanup(RERR_PROTOCOL); |  | ||||||
|  		} |  | ||||||
|   |  | ||||||
| -		fd = do_open(fname, O_RDONLY, 0);
 |  | ||||||
| +		fd = do_open_checklinks(fname);
 |  | ||||||
|  		if (fd == -1) { |  | ||||||
|  			if (errno == ENOENT) { |  | ||||||
|  				enum logcode c = am_daemon |  | ||||||
| diff --git a/syscall.c b/syscall.c
 |  | ||||||
| index 47c5ea5..c55ae5f 100644
 |  | ||||||
| --- a/syscall.c
 |  | ||||||
| +++ b/syscall.c
 |  | ||||||
| @@ -45,6 +45,8 @@ extern int preallocate_files;
 |  | ||||||
|  extern int preallocate_files; |  | ||||||
|  extern int preserve_perms; |  | ||||||
|  extern int preserve_executability; |  | ||||||
| +extern int copy_links;
 |  | ||||||
| +extern int copy_unsafe_links;
 |  | ||||||
|   |  | ||||||
|  #ifndef S_BLKSIZE |  | ||||||
|  # if defined hpux || defined __hpux__ || defined __hpux |  | ||||||
| @@ -575,3 +575,21 @@ int do_open_nofollow(const char *pathname, int flags)
 |  | ||||||
|   |  | ||||||
|  	return fd; |  | ||||||
|  } |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| +  varient of do_open/do_open_nofollow which does do_open() if the
 |  | ||||||
| +  copy_links or copy_unsafe_links options are set and does
 |  | ||||||
| +  do_open_nofollow() otherwise
 |  | ||||||
| +
 |  | ||||||
| +  This is used to prevent a race condition where an attacker could be
 |  | ||||||
| +  switching a file between being a symlink and being a normal file
 |  | ||||||
| +
 |  | ||||||
| +  The open is always done with O_RDONLY flags
 |  | ||||||
| + */
 |  | ||||||
| +int do_open_checklinks(const char *pathname)
 |  | ||||||
| +{
 |  | ||||||
| + if (copy_links || copy_unsafe_links) {
 |  | ||||||
| +   return do_open(pathname, O_RDONLY, 0);
 |  | ||||||
| + }
 |  | ||||||
| + return do_open_nofollow(pathname, O_RDONLY);
 |  | ||||||
| +}
 |  | ||||||
| diff --git a/t_unsafe.c b/t_unsafe.c
 |  | ||||||
| index 010cac5..e10619a 100644
 |  | ||||||
| --- a/t_unsafe.c
 |  | ||||||
| +++ b/t_unsafe.c
 |  | ||||||
| @@ -28,6 +28,9 @@ int am_root = 0;
 |  | ||||||
|  int human_readable = 0; |  | ||||||
|  int preserve_perms = 0; |  | ||||||
|  int preserve_executability = 0; |  | ||||||
| +int copy_links = 0;
 |  | ||||||
| +int copy_unsafe_links = 0;
 |  | ||||||
| +
 |  | ||||||
|  short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG]; |  | ||||||
|   |  | ||||||
|  int |  | ||||||
| diff --git a/tls.c b/tls.c
 |  | ||||||
| index e6b0708..858f8f1 100644
 |  | ||||||
| --- a/tls.c
 |  | ||||||
| +++ b/tls.c
 |  | ||||||
| @@ -49,6 +49,9 @@ int list_only = 0;
 |  | ||||||
|  int preserve_executability = 0; |  | ||||||
|  int preallocate_files = 0; |  | ||||||
|  int inplace = 0; |  | ||||||
| +int safe_symlinks = 0;
 |  | ||||||
| +int copy_links = 0;
 |  | ||||||
| +int copy_unsafe_links = 0;
 |  | ||||||
|   |  | ||||||
|  #ifdef SUPPORT_XATTRS |  | ||||||
|   |  | ||||||
| diff --git a/trimslash.c b/trimslash.c
 |  | ||||||
| index 1ec928c..f2774cd 100644
 |  | ||||||
| --- a/trimslash.c
 |  | ||||||
| +++ b/trimslash.c
 |  | ||||||
| @@ -26,6 +26,8 @@ int am_root = 0;
 |  | ||||||
|  int preserve_executability = 0; |  | ||||||
|  int preallocate_files = 0; |  | ||||||
|  int inplace = 0; |  | ||||||
| +int copy_links = 0;
 |  | ||||||
| +int copy_unsafe_links = 0;
 |  | ||||||
|   |  | ||||||
|  int |  | ||||||
|  main(int argc, char **argv) |  | ||||||
| diff --git a/util.c b/util.c
 |  | ||||||
| index f260d39..d84bc41 100644
 |  | ||||||
| --- a/util.c
 |  | ||||||
| +++ b/util.c
 |  | ||||||
| @@ -365,7 +365,7 @@ int copy_file(const char *source, const char *dest, int tmpfilefd, mode_t mode)
 |  | ||||||
|  	int len;   /* Number of bytes read into `buf'. */ |  | ||||||
|  	OFF_T prealloc_len = 0, offset = 0; |  | ||||||
|   |  | ||||||
| -	if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
 |  | ||||||
| +	if ((ifd = do_open_nofollow(source, O_RDONLY)) < 0) {
 |  | ||||||
|  		int save_errno = errno; |  | ||||||
|  		rsyserr(FERROR_XFER, errno, "open %s", full_fname(source)); |  | ||||||
|  		errno = save_errno; |  | ||||||
| @ -1,54 +0,0 @@ | |||||||
| diff --git a/zlib/inftrees.c b/zlib/inftrees.c
 |  | ||||||
| index 44d89cf2..571e8100 100644
 |  | ||||||
| --- a/zlib/inftrees.c
 |  | ||||||
| +++ b/zlib/inftrees.c
 |  | ||||||
| @@ -54,7 +54,7 @@ unsigned short FAR *work;
 |  | ||||||
|      code FAR *next;             /* next available space in table */ |  | ||||||
|      const unsigned short FAR *base;     /* base value table to use */ |  | ||||||
|      const unsigned short FAR *extra;    /* extra bits table to use */ |  | ||||||
| -    int end;                    /* use base and extra for symbol > end */
 |  | ||||||
| +    unsigned match;             /* use base and extra for symbol >= match */
 |  | ||||||
|      unsigned short count[MAXBITS+1];    /* number of codes of each length */ |  | ||||||
|      unsigned short offs[MAXBITS+1];     /* offsets in table for each length */ |  | ||||||
|      static const unsigned short lbase[31] = { /* Length codes 257..285 base */ |  | ||||||
| @@ -181,19 +181,17 @@ unsigned short FAR *work;
 |  | ||||||
|      switch (type) { |  | ||||||
|      case CODES: |  | ||||||
|          base = extra = work;    /* dummy value--not used */ |  | ||||||
| -        end = 19;
 |  | ||||||
| +        match = 20;
 |  | ||||||
|          break; |  | ||||||
|      case LENS: |  | ||||||
|          base = lbase; |  | ||||||
| -        base -= 257;
 |  | ||||||
|          extra = lext; |  | ||||||
| -        extra -= 257;
 |  | ||||||
| -        end = 256;
 |  | ||||||
| +        match = 257;
 |  | ||||||
|          break; |  | ||||||
|      default:            /* DISTS */ |  | ||||||
|          base = dbase; |  | ||||||
|          extra = dext; |  | ||||||
| -        end = -1;
 |  | ||||||
| +        match = 0;
 |  | ||||||
|      } |  | ||||||
|   |  | ||||||
|      /* initialize state for loop */ |  | ||||||
| @@ -216,13 +214,13 @@ unsigned short FAR *work;
 |  | ||||||
|      for (;;) { |  | ||||||
|          /* create table entry */ |  | ||||||
|          here.bits = (unsigned char)(len - drop); |  | ||||||
| -        if ((int)(work[sym]) < end) {
 |  | ||||||
| +        if (work[sym] + 1u < match) {
 |  | ||||||
|              here.op = (unsigned char)0; |  | ||||||
|              here.val = work[sym]; |  | ||||||
|          } |  | ||||||
| -        else if ((int)(work[sym]) > end) {
 |  | ||||||
| -            here.op = (unsigned char)(extra[work[sym]]);
 |  | ||||||
| -            here.val = base[work[sym]];
 |  | ||||||
| +        else if (work[sym] >= match) {
 |  | ||||||
| +            here.op = (unsigned char)(extra[work[sym] - match]);
 |  | ||||||
| +            here.val = base[work[sym] - match];
 |  | ||||||
|          } |  | ||||||
|          else { |  | ||||||
|              here.op = (unsigned char)(32 + 64);         /* end of block */ |  | ||||||
| @ -1,333 +0,0 @@ | |||||||
| diff --git a/exclude.c b/exclude.c
 |  | ||||||
| index 13c4253..232249f 100644
 |  | ||||||
| --- a/exclude.c
 |  | ||||||
| +++ b/exclude.c
 |  | ||||||
| @@ -79,6 +79,10 @@ static filter_rule **mergelist_parents;
 |  | ||||||
|  static int mergelist_cnt = 0; |  | ||||||
|  static int mergelist_size = 0; |  | ||||||
|   |  | ||||||
| +#define LOCAL_RULE   1
 |  | ||||||
| +#define REMOTE_RULE  2
 |  | ||||||
| +static uchar cur_elide_value = REMOTE_RULE;
 |  | ||||||
| +
 |  | ||||||
|  /* Each filter_list_struct describes a singly-linked list by keeping track |  | ||||||
|   * of both the head and tail pointers.  The list is slightly unusual in that |  | ||||||
|   * a parent-dir's content can be appended to the end of the local list in a |  | ||||||
| @@ -218,6 +222,7 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
 |  | ||||||
|  				slash_cnt++; |  | ||||||
|  		} |  | ||||||
|  	} |  | ||||||
| +	rule->elide = 0;
 |  | ||||||
|  	strlcpy(rule->pattern + pre_len, pat, pat_len + 1); |  | ||||||
|  	pat_len += pre_len; |  | ||||||
|  	if (suf_len) { |  | ||||||
| @@ -364,6 +369,8 @@ void implied_include_partial_string(const char *s_start, const char *s_end)
 |  | ||||||
|  void free_implied_include_partial_string() |  | ||||||
|  { |  | ||||||
|  	if (partial_string_buf) { |  | ||||||
| +		if (partial_string_len)
 |  | ||||||
| +			add_implied_include("", 0);
 |  | ||||||
|  		free(partial_string_buf); |  | ||||||
|  		partial_string_buf = NULL; |  | ||||||
|  	} |  | ||||||
| @@ -374,9 +381,8 @@ void free_implied_include_partial_string()
 |  | ||||||
|   * that the receiver uses to validate the file list from the sender. */ |  | ||||||
|  void add_implied_include(const char *arg, int skip_daemon_module) |  | ||||||
|  { |  | ||||||
| -	filter_rule *rule;
 |  | ||||||
|  	int arg_len, saw_wild = 0, saw_live_open_brkt = 0, backslash_cnt = 0; |  | ||||||
| -	int slash_cnt = 1; /* We know we're adding a leading slash. */
 |  | ||||||
| +	int slash_cnt = 0;
 |  | ||||||
|  	const char *cp; |  | ||||||
|  	char *p; |  | ||||||
|  	if (am_server || old_style_args || list_only || read_batch || filesfrom_host != NULL) |  | ||||||
| @@ -407,6 +413,7 @@ void add_implied_include(const char *arg, int skip_daemon_module)
 |  | ||||||
|  		arg++; |  | ||||||
|  	arg_len = strlen(arg); |  | ||||||
|  	if (arg_len) { |  | ||||||
| +		char *new_pat;
 |  | ||||||
|  		if (strpbrk(arg, "*[?")) { |  | ||||||
|  			/* We need to add room to escape backslashes if wildcard chars are present. */ |  | ||||||
|  			for (cp = arg; (cp = strchr(cp, '\\')) != NULL; cp++) |  | ||||||
| @@ -414,16 +421,9 @@ void add_implied_include(const char *arg, int skip_daemon_module)
 |  | ||||||
|  			saw_wild = 1; |  | ||||||
|  		} |  | ||||||
|  		arg_len++; /* Leave room for the prefixed slash */ |  | ||||||
| -		rule = new0(filter_rule);
 |  | ||||||
| -		if (!implied_filter_list.head)
 |  | ||||||
| -			implied_filter_list.head = implied_filter_list.tail = rule;
 |  | ||||||
| -		else {
 |  | ||||||
| -			rule->next = implied_filter_list.head;
 |  | ||||||
| -			implied_filter_list.head = rule;
 |  | ||||||
| -		}
 |  | ||||||
| -		rule->rflags = FILTRULE_INCLUDE + (saw_wild ? FILTRULE_WILD : 0);
 |  | ||||||
| -		p = rule->pattern = new_array(char, arg_len + 1);
 |  | ||||||
| +		p = new_pat = new_array(char, arg_len + 1);
 |  | ||||||
|  		*p++ = '/'; |  | ||||||
| +		slash_cnt++;
 |  | ||||||
|  		for (cp = arg; *cp; ) { |  | ||||||
|  			switch (*cp) { |  | ||||||
|  			  case '\\': |  | ||||||
| @@ -439,15 +439,70 @@ void add_implied_include(const char *arg, int skip_daemon_module)
 |  | ||||||
|  				break; |  | ||||||
|  			  case '/': |  | ||||||
|  				if (p[-1] == '/') { /* This is safe because of the initial slash. */ |  | ||||||
| +					if (*++cp == '\0') {
 |  | ||||||
| +						slash_cnt--;
 |  | ||||||
| +						p--;
 |  | ||||||
| +					}
 |  | ||||||
| +				} else if (cp[1] == '\0') {
 |  | ||||||
|  					cp++; |  | ||||||
| -					break;
 |  | ||||||
| +				} else {
 |  | ||||||
| +					slash_cnt++;
 |  | ||||||
| +					*p++ = *cp++;
 |  | ||||||
|  				} |  | ||||||
| -				if (relative_paths) {
 |  | ||||||
| -					filter_rule const *ent;
 |  | ||||||
| +				break;
 |  | ||||||
| +			  case '.':
 |  | ||||||
| +				if (p[-1] == '/') {
 |  | ||||||
| +					if (cp[1] == '/') {
 |  | ||||||
| +						cp += 2;
 |  | ||||||
| +						if (!*cp) {
 |  | ||||||
| +							slash_cnt--;
 |  | ||||||
| +							p--;
 |  | ||||||
| +						}
 |  | ||||||
| +					} else if (cp[1] == '\0') {
 |  | ||||||
| +						cp++;
 |  | ||||||
| +						slash_cnt--;
 |  | ||||||
| +						p--;
 |  | ||||||
| +					} else
 |  | ||||||
| +						*p++ = *cp++;
 |  | ||||||
| +				} else
 |  | ||||||
| +					*p++ = *cp++;
 |  | ||||||
| +				break;
 |  | ||||||
| +			  case '[':
 |  | ||||||
| +				saw_live_open_brkt = 1;
 |  | ||||||
| +				*p++ = *cp++;
 |  | ||||||
| +				break;
 |  | ||||||
| +			  default:
 |  | ||||||
| +				*p++ = *cp++;
 |  | ||||||
| +				break;
 |  | ||||||
| +			}
 |  | ||||||
| +		}
 |  | ||||||
| +		*p = '\0';
 |  | ||||||
| +		arg_len = p - new_pat;
 |  | ||||||
| +		if (!arg_len)
 |  | ||||||
| +			free(new_pat);
 |  | ||||||
| +		else {
 |  | ||||||
| +			filter_rule *rule = new0(filter_rule);
 |  | ||||||
| +			rule->rflags = FILTRULE_INCLUDE + (saw_wild ? FILTRULE_WILD : 0);
 |  | ||||||
| +			rule->u.slash_cnt = slash_cnt;
 |  | ||||||
| +			arg = rule->pattern = new_pat;
 |  | ||||||
| +			if (!implied_filter_list.head)
 |  | ||||||
| +				implied_filter_list.head = implied_filter_list.tail = rule;
 |  | ||||||
| +			else {
 |  | ||||||
| +				rule->next = implied_filter_list.head;
 |  | ||||||
| +				implied_filter_list.head = rule;
 |  | ||||||
| +			}
 |  | ||||||
| +			if (DEBUG_GTE(FILTER, 3))
 |  | ||||||
| +				rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), arg);
 |  | ||||||
| +			if (saw_live_open_brkt)
 |  | ||||||
| +				maybe_add_literal_brackets_rule(rule, arg_len);
 |  | ||||||
| +			if (relative_paths && slash_cnt) {
 |  | ||||||
| +				filter_rule const *ent;
 |  | ||||||
| +				slash_cnt = 1;
 |  | ||||||
| +				for (p = new_pat + 1; (p = strchr(p, '/')) != NULL; p++) {
 |  | ||||||
|  					int found = 0; |  | ||||||
|  					*p = '\0'; |  | ||||||
|  					for (ent = implied_filter_list.head; ent; ent = ent->next) { |  | ||||||
| -						if (ent != rule && strcmp(ent->pattern, rule->pattern) == 0) {
 |  | ||||||
| +						if (ent != rule && strcmp(ent->pattern, new_pat) == 0) {
 |  | ||||||
|  							found = 1; |  | ||||||
|  							break; |  | ||||||
|  						} |  | ||||||
| @@ -456,9 +511,9 @@ void add_implied_include(const char *arg, int skip_daemon_module)
 |  | ||||||
|  						filter_rule *R_rule = new0(filter_rule); |  | ||||||
|  						R_rule->rflags = FILTRULE_INCLUDE | FILTRULE_DIRECTORY; |  | ||||||
|  						/* Check if our sub-path has wildcards or escaped backslashes */ |  | ||||||
| -						if (saw_wild && strpbrk(rule->pattern, "*[?\\"))
 |  | ||||||
| +						if (saw_wild && strpbrk(new_pat, "*[?\\"))
 |  | ||||||
|  							R_rule->rflags |= FILTRULE_WILD; |  | ||||||
| -						R_rule->pattern = strdup(rule->pattern);
 |  | ||||||
| +						R_rule->pattern = strdup(new_pat);
 |  | ||||||
|  						R_rule->u.slash_cnt = slash_cnt; |  | ||||||
|  						R_rule->next = implied_filter_list.head; |  | ||||||
|  						implied_filter_list.head = R_rule; |  | ||||||
| @@ -469,32 +524,16 @@ void add_implied_include(const char *arg, int skip_daemon_module)
 |  | ||||||
|  						if (saw_live_open_brkt) |  | ||||||
|  							maybe_add_literal_brackets_rule(R_rule, -1); |  | ||||||
|  					} |  | ||||||
| +					*p = '/';
 |  | ||||||
| +					slash_cnt++;
 |  | ||||||
|  				} |  | ||||||
| -				slash_cnt++;
 |  | ||||||
| -				*p++ = *cp++;
 |  | ||||||
| -				break;
 |  | ||||||
| -			  case '[':
 |  | ||||||
| -				saw_live_open_brkt = 1;
 |  | ||||||
| -				*p++ = *cp++;
 |  | ||||||
| -				break;
 |  | ||||||
| -			  default:
 |  | ||||||
| -				*p++ = *cp++;
 |  | ||||||
| -				break;
 |  | ||||||
|  			} |  | ||||||
|  		} |  | ||||||
| -		*p = '\0';
 |  | ||||||
| -		rule->u.slash_cnt = slash_cnt;
 |  | ||||||
| -		arg = rule->pattern;
 |  | ||||||
| -		arg_len = p - arg; /* We recompute it due to backslash weirdness. */
 |  | ||||||
| -		if (DEBUG_GTE(FILTER, 3))
 |  | ||||||
| -			rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), rule->pattern);
 |  | ||||||
| -		if (saw_live_open_brkt)
 |  | ||||||
| -			maybe_add_literal_brackets_rule(rule, arg_len);
 |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
|  	if (recurse || xfer_dirs) { |  | ||||||
|  		/* Now create a rule with an added "/" & "**" or "*" at the end */ |  | ||||||
| -		rule = new0(filter_rule);
 |  | ||||||
| +		filter_rule *rule = new0(filter_rule);
 |  | ||||||
|  		rule->rflags = FILTRULE_INCLUDE | FILTRULE_WILD; |  | ||||||
|  		if (recurse) |  | ||||||
|  			rule->rflags |= FILTRULE_WILD2; |  | ||||||
| @@ -502,7 +541,7 @@ void add_implied_include(const char *arg, int skip_daemon_module)
 |  | ||||||
|  		if (!saw_wild && backslash_cnt) { |  | ||||||
|  			/* We are appending a wildcard, so now the backslashes need to be escaped. */ |  | ||||||
|  			p = rule->pattern = new_array(char, arg_len + backslash_cnt + 3 + 1); |  | ||||||
| -			for (cp = arg; *cp; ) {
 |  | ||||||
| +			for (cp = arg; *cp; ) { /* Note that arg_len != 0 because backslash_cnt > 0 */
 |  | ||||||
|  				if (*cp == '\\') |  | ||||||
|  					*p++ = '\\'; |  | ||||||
|  				*p++ = *cp++; |  | ||||||
| @@ -514,13 +553,15 @@ void add_implied_include(const char *arg, int skip_daemon_module)
 |  | ||||||
|  				p += arg_len; |  | ||||||
|  			} |  | ||||||
|  		} |  | ||||||
| -		if (p[-1] != '/')
 |  | ||||||
| +		if (p[-1] != '/') {
 |  | ||||||
|  			*p++ = '/'; |  | ||||||
| +			slash_cnt++;
 |  | ||||||
| +		}
 |  | ||||||
|  		*p++ = '*'; |  | ||||||
|  		if (recurse) |  | ||||||
|  			*p++ = '*'; |  | ||||||
|  		*p = '\0'; |  | ||||||
| -		rule->u.slash_cnt = slash_cnt + 1;
 |  | ||||||
| +		rule->u.slash_cnt = slash_cnt;
 |  | ||||||
|  		rule->next = implied_filter_list.head; |  | ||||||
|  		implied_filter_list.head = rule; |  | ||||||
|  		if (DEBUG_GTE(FILTER, 3)) |  | ||||||
| @@ -869,7 +910,7 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_flags)
 |  | ||||||
|  	const char *strings[16]; /* more than enough */ |  | ||||||
|  	const char *name = fname + (*fname == '/'); |  | ||||||
|   |  | ||||||
| -	if (!*name)
 |  | ||||||
| +	if (!*name || ex->elide == cur_elide_value)
 |  | ||||||
|  		return 0; |  | ||||||
|   |  | ||||||
|  	if (!(name_flags & NAME_IS_XATTR) ^ !(ex->rflags & FILTRULE_XATTR)) |  | ||||||
| @@ -985,6 +1026,15 @@ int name_is_excluded(const char *fname, int name_flags, int filter_level)
 |  | ||||||
|  	return 0; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +int check_server_filter(filter_rule_list *listp, enum logcode code, const char *name, int name_flags)
 |  | ||||||
| +{
 |  | ||||||
| +	int ret;
 |  | ||||||
| +	cur_elide_value = LOCAL_RULE;
 |  | ||||||
| +	ret = check_filter(listp, code, name, name_flags);
 |  | ||||||
| +	cur_elide_value = REMOTE_RULE;
 |  | ||||||
| +	return ret;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
|  /* Return -1 if file "name" is defined to be excluded by the specified |  | ||||||
|   * exclude list, 1 if it is included, and 0 if it was not matched. */ |  | ||||||
|  int check_filter(filter_rule_list *listp, enum logcode code, |  | ||||||
| @@ -1550,7 +1600,7 @@ char *get_rule_prefix(filter_rule *rule, const char *pat, int for_xfer,
 |  | ||||||
|   |  | ||||||
|  static void send_rules(int f_out, filter_rule_list *flp) |  | ||||||
|  { |  | ||||||
| -	filter_rule *ent, *prev = NULL;
 |  | ||||||
| +	filter_rule *ent;
 |  | ||||||
|   |  | ||||||
|  	for (ent = flp->head; ent; ent = ent->next) { |  | ||||||
|  		unsigned int len, plen, dlen; |  | ||||||
| @@ -1565,21 +1615,15 @@ static void send_rules(int f_out, filter_rule_list *flp)
 |  | ||||||
|  		 * merge files as an optimization (since they can only have |  | ||||||
|  		 * include/exclude rules). */ |  | ||||||
|  		if (ent->rflags & FILTRULE_SENDER_SIDE) |  | ||||||
| -			elide = am_sender ? 1 : -1;
 |  | ||||||
| +			elide = am_sender ? LOCAL_RULE : REMOTE_RULE;
 |  | ||||||
|  		if (ent->rflags & FILTRULE_RECEIVER_SIDE) |  | ||||||
| -			elide = elide ? 0 : am_sender ? -1 : 1;
 |  | ||||||
| +			elide = elide ? 0 : am_sender ? REMOTE_RULE : LOCAL_RULE;
 |  | ||||||
|  		else if (delete_excluded && !elide |  | ||||||
|  		 && (!(ent->rflags & FILTRULE_PERDIR_MERGE) |  | ||||||
|  		  || ent->rflags & FILTRULE_NO_PREFIXES)) |  | ||||||
| -			elide = am_sender ? 1 : -1;
 |  | ||||||
| -		if (elide < 0) {
 |  | ||||||
| -			if (prev)
 |  | ||||||
| -				prev->next = ent->next;
 |  | ||||||
| -			else
 |  | ||||||
| -				flp->head = ent->next;
 |  | ||||||
| -		} else
 |  | ||||||
| -			prev = ent;
 |  | ||||||
| -		if (elide > 0)
 |  | ||||||
| +			elide = am_sender ? LOCAL_RULE : REMOTE_RULE;
 |  | ||||||
| +		ent->elide = elide;
 |  | ||||||
| +		if (elide == LOCAL_RULE)
 |  | ||||||
|  			continue; |  | ||||||
|  		if (ent->rflags & FILTRULE_CVS_IGNORE |  | ||||||
|  		    && !(ent->rflags & FILTRULE_MERGE_FILE)) { |  | ||||||
| @@ -1607,7 +1651,6 @@ static void send_rules(int f_out, filter_rule_list *flp)
 |  | ||||||
|  		if (dlen) |  | ||||||
|  			write_byte(f_out, '/'); |  | ||||||
|  	} |  | ||||||
| -	flp->tail = prev;
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  /* This is only called by the client. */ |  | ||||||
| diff --git a/options.c b/options.c
 |  | ||||||
| index afc33ce..4d0a1a6 100644
 |  | ||||||
| --- a/options.c
 |  | ||||||
| +++ b/options.c
 |  | ||||||
| @@ -2426,7 +2426,9 @@ char *safe_arg(const char *opt, const char *arg)
 |  | ||||||
|  	char *ret; |  | ||||||
|  	if (!protect_args && old_style_args < 2 && (!old_style_args || (!is_filename_arg && opt != SPLIT_ARG_WHEN_OLD))) { |  | ||||||
|  		const char *f; |  | ||||||
| -		if (!old_style_args && *arg == '~' && (relative_paths || !strchr(arg, '/'))) {
 |  | ||||||
| +		if (!old_style_args && *arg == '~' 
 |  | ||||||
| +				&& ((relative_paths && !strstr(arg, "/./")) 
 |  | ||||||
| +				|| !strchr(arg, '/'))) {
 |  | ||||||
|  			extras++; |  | ||||||
|  			escape_leading_tilde = 1; |  | ||||||
|  		} |  | ||||||
| diff --git a/flist.c b/flist.c
 |  | ||||||
| index 630d685..8c2397b 100644
 |  | ||||||
| --- a/flist.c
 |  | ||||||
| +++ b/flist.c
 |  | ||||||
| @@ -904,10 +904,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
 |  | ||||||
|  		exit_cleanup(RERR_UNSUPPORTED); |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| -	if (*thisname != '.' || thisname[1] != '\0') {
 |  | ||||||
| +	if (*thisname == '/' ? thisname[1] != '.' || thisname[2] != '\0' : *thisname != '.' || thisname[1] != '\0') {
 |  | ||||||
|  		int filt_flags = S_ISDIR(mode) ? NAME_IS_DIR : NAME_IS_FILE; |  | ||||||
|  		if (!trust_sender_filter /* a per-dir filter rule means we must trust the sender's filtering */ |  | ||||||
| -		 && filter_list.head && check_filter(&filter_list, FINFO, thisname, filt_flags) < 0) {
 |  | ||||||
| +		 && filter_list.head && check_server_filter(&filter_list, FINFO, thisname, filt_flags) < 0) {
 |  | ||||||
|  			rprintf(FERROR, "ERROR: rejecting excluded file-list name: %s\n", thisname); |  | ||||||
|  			exit_cleanup(RERR_PROTOCOL); |  | ||||||
|  		} |  | ||||||
| diff --git a/rsync.h b/rsync.h
 |  | ||||||
| index 53fff2d..b357dad 100644
 |  | ||||||
| --- a/rsync.h
 |  | ||||||
| +++ b/rsync.h
 |  | ||||||
| @@ -899,6 +899,7 @@ typedef struct filter_struct {
 |  | ||||||
|  		int slash_cnt; |  | ||||||
|  		struct filter_list_struct *mergelist; |  | ||||||
|  	} u; |  | ||||||
| +	uchar elide;
 |  | ||||||
|  } filter_rule; |  | ||||||
|   |  | ||||||
|  typedef struct filter_list_struct { |  | ||||||
| @ -1,49 +0,0 @@ | |||||||
| commit af6118d98b3482cbcfc223bf2a0777bc19eccb02 |  | ||||||
| Author: Wayne Davison <wayne@opencoder.net> |  | ||||||
| Date:   Sun Apr 26 18:02:17 2020 -0700 |  | ||||||
| 
 |  | ||||||
|     Allow a missing parent dir when --delete-missing-args was specified. |  | ||||||
| 
 |  | ||||||
| diff --git a/generator.c b/generator.c
 |  | ||||||
| index 3c50f63f..b90c7ccd 100644
 |  | ||||||
| --- a/generator.c
 |  | ||||||
| +++ b/generator.c
 |  | ||||||
| @@ -1277,10 +1277,16 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 |  | ||||||
|  			 && (*dn != '.' || dn[1]) /* Avoid an issue with --relative and the "." dir. */ |  | ||||||
|  			 && (!prior_dir_file || strcmp(dn, f_name(prior_dir_file, NULL)) != 0) |  | ||||||
|  			 && flist_find_name(cur_flist, dn, 1) < 0) { |  | ||||||
| -				rprintf(FERROR,
 |  | ||||||
| -					"ABORTING due to invalid path from sender: %s/%s\n",
 |  | ||||||
| -					dn, file->basename);
 |  | ||||||
| -				exit_cleanup(RERR_PROTOCOL);
 |  | ||||||
| +				/* The --delete-missing-args option can actually put invalid entries into
 |  | ||||||
| +				 * the file list, so if that option was specified, we'll just complain about
 |  | ||||||
| +				 * it and allow it. */
 |  | ||||||
| +				if (missing_args == 2 && file->mode == 0)
 |  | ||||||
| +					rprintf(FERROR, "WARNING: parent dir is absent in the file list: %s\n", dn);
 |  | ||||||
| +				else {
 |  | ||||||
| +					rprintf(FERROR, "ABORTING due to invalid path from sender: %s/%s\n",
 |  | ||||||
| +						dn, file->basename);
 |  | ||||||
| +					exit_cleanup(RERR_PROTOCOL);
 |  | ||||||
| +				}
 |  | ||||||
|  			} |  | ||||||
|  			if (relative_paths && !implied_dirs |  | ||||||
|  			 && do_stat(dn, &sx.st) < 0) { |  | ||||||
| @@ -1383,7 +1389,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 |  | ||||||
|  			added_perms = 0; |  | ||||||
|  		if (is_dir < 0) { |  | ||||||
|  			if (!(preserve_times & PRESERVE_DIR_TIMES)) |  | ||||||
| -				return;
 |  | ||||||
| +				goto cleanup;
 |  | ||||||
|  			/* In inc_recurse mode we want to make sure any missing |  | ||||||
|  			 * directories get created while we're still processing |  | ||||||
|  			 * the parent dir (which allows us to touch the parent |  | ||||||
| @@ -1525,7 +1531,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 |  | ||||||
|  					"ignoring unsafe symlink \"%s\" -> \"%s\"\n", |  | ||||||
|  					fname, sl); |  | ||||||
|  			} |  | ||||||
| -			return;
 |  | ||||||
| +			goto cleanup;
 |  | ||||||
|  		} |  | ||||||
|  		if (statret == 0) { |  | ||||||
|  			char lnk[MAXPATHLEN]; |  | ||||||
| @ -1,13 +0,0 @@ | |||||||
| diff --git a/exclude.c.old b/exclude.c
 |  | ||||||
| index 232249f..2f6dccc 100644
 |  | ||||||
| --- a/exclude.c.old
 |  | ||||||
| +++ b/exclude.c
 |  | ||||||
| @@ -1575,6 +1575,8 @@ char *get_rule_prefix(filter_rule *rule, const char *pat, int for_xfer,
 |  | ||||||
|  	} |  | ||||||
|  	if (rule->rflags & FILTRULE_EXCLUDE_SELF) |  | ||||||
|  		*op++ = 'e'; |  | ||||||
| +	if (rule->rflags & FILTRULE_XATTR)
 |  | ||||||
| +		*op++ = 'x';
 |  | ||||||
|  	if (rule->rflags & FILTRULE_SENDER_SIDE |  | ||||||
|  	    && (!for_xfer || protocol_version >= 29)) |  | ||||||
|  		*op++ = 's'; |  | ||||||
| @ -1,37 +0,0 @@ | |||||||
| diff --git a/loadparm.c b/loadparm.c
 |  | ||||||
| index 029f358f..534e7b63 100644
 |  | ||||||
| --- a/loadparm.c
 |  | ||||||
| +++ b/loadparm.c
 |  | ||||||
| @@ -449,7 +449,7 @@ static struct parm_struct parm_table[] =
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  /* Initialise the Default all_vars structure. */ |  | ||||||
| -static void reset_all_vars(void)
 |  | ||||||
| +void reset_daemon_vars(void)
 |  | ||||||
|  { |  | ||||||
|  	memcpy(&Vars, &Defaults, sizeof Vars); |  | ||||||
|  } |  | ||||||
| @@ -872,7 +872,7 @@ int lp_load(char *pszFname, int globals_only)
 |  | ||||||
|  { |  | ||||||
|  	bInGlobalSection = True; |  | ||||||
|   |  | ||||||
| -	reset_all_vars();
 |  | ||||||
| +	reset_daemon_vars();
 |  | ||||||
|   |  | ||||||
|  	/* We get sections first, so have to start 'behind' to make up. */ |  | ||||||
|  	iSectionIndex = -1; |  | ||||||
| diff --git a/main.c b/main.c
 |  | ||||||
| index 1328c504..9af9e5d3 100644
 |  | ||||||
| --- a/main.c
 |  | ||||||
| +++ b/main.c
 |  | ||||||
| @@ -1681,6 +1681,10 @@ int main(int argc,char *argv[])
 |  | ||||||
|   |  | ||||||
|  	memset(&stats, 0, sizeof(stats)); |  | ||||||
|   |  | ||||||
| +	/* Even a non-daemon runs needs the default config values to be set, e.g.
 |  | ||||||
| +	 * lp_dont_compress() is queried when no --skip-compress option is set. */
 |  | ||||||
| +	reset_daemon_vars();
 |  | ||||||
| +
 |  | ||||||
|  	if (argc < 2) { |  | ||||||
|  		usage(FERROR); |  | ||||||
|  		exit_cleanup(RERR_SYNTAX); |  | ||||||
| @ -1,122 +0,0 @@ | |||||||
| diff --git a/fileio.c b/fileio.c
 |  | ||||||
| index b183e20..72d6076 100644
 |  | ||||||
| --- a/fileio.c
 |  | ||||||
| +++ b/fileio.c
 |  | ||||||
| @@ -34,6 +34,7 @@
 |  | ||||||
|  #define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDRY-1)) + 1) |  | ||||||
|   |  | ||||||
|  extern int sparse_files; |  | ||||||
| +extern int sparse_files_block_size;
 |  | ||||||
|   |  | ||||||
|  OFF_T preallocated_len = 0; |  | ||||||
|   |  | ||||||
| @@ -147,7 +148,7 @@ int write_file(int f, int use_seek, OFF_T offset, const char *buf, int len)
 |  | ||||||
|  	while (len > 0) { |  | ||||||
|  		int r1; |  | ||||||
|  		if (sparse_files > 0) { |  | ||||||
| -			int len1 = MIN(len, SPARSE_WRITE_SIZE);
 |  | ||||||
| +			int len1 = MIN(len, sparse_files_block_size ? sparse_files_block_size : SPARSE_WRITE_SIZE);
 |  | ||||||
|  			r1 = write_sparse(f, use_seek, offset, buf, len1); |  | ||||||
|  			offset += r1; |  | ||||||
|  		} else { |  | ||||||
| diff --git a/options.c b/options.c
 |  | ||||||
| index 195672e..d08c05a 100644
 |  | ||||||
| --- a/options.c
 |  | ||||||
| +++ b/options.c
 |  | ||||||
| @@ -76,6 +76,7 @@ int remove_source_files = 0;
 |  | ||||||
|  int one_file_system = 0; |  | ||||||
|  int protocol_version = PROTOCOL_VERSION; |  | ||||||
|  int sparse_files = 0; |  | ||||||
| +long sparse_files_block_size = 0;
 |  | ||||||
|  int preallocate_files = 0; |  | ||||||
|  int do_compression = 0; |  | ||||||
|  int def_compress_level = NOT_SPECIFIED; |  | ||||||
| @@ -717,6 +718,7 @@ void usage(enum logcode F)
 |  | ||||||
|    rprintf(F,"     --fake-super            store/recover privileged attrs using xattrs\n"); |  | ||||||
|  #endif |  | ||||||
|    rprintf(F," -S, --sparse                turn sequences of nulls into sparse blocks\n"); |  | ||||||
| +  rprintf(F,"     --sparse-block=SIZE     set block size used to handle sparse files\n");
 |  | ||||||
|  #ifdef SUPPORT_PREALLOCATION |  | ||||||
|    rprintf(F,"     --preallocate           allocate dest files before writing them\n"); |  | ||||||
|  #else |  | ||||||
| @@ -927,6 +929,7 @@ static struct poptOption long_options[] = {
 |  | ||||||
|    {"sparse",          'S', POPT_ARG_VAL,    &sparse_files, 1, 0, 0 }, |  | ||||||
|    {"no-sparse",        0,  POPT_ARG_VAL,    &sparse_files, 0, 0, 0 }, |  | ||||||
|    {"no-S",             0,  POPT_ARG_VAL,    &sparse_files, 0, 0, 0 }, |  | ||||||
| +  {"sparse-block",     0,  POPT_ARG_LONG,   &sparse_files_block_size, 0, 0, 0 },
 |  | ||||||
|    {"preallocate",      0,  POPT_ARG_NONE,   &preallocate_files, 0, 0, 0}, |  | ||||||
|    {"inplace",          0,  POPT_ARG_VAL,    &inplace, 1, 0, 0 }, |  | ||||||
|    {"no-inplace",       0,  POPT_ARG_VAL,    &inplace, 0, 0, 0 }, |  | ||||||
| diff --git a/options.c b/options.c
 |  | ||||||
| index b12da55..5a27452 100644
 |  | ||||||
| --- a/options.c
 |  | ||||||
| +++ b/options.c
 |  | ||||||
| @@ -2606,6 +2606,12 @@ void server_options(char **args, int *argc_p)
 |  | ||||||
|  		args[ac++] = arg; |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| +	if (sparse_files_block_size) {
 |  | ||||||
| +		if (asprintf(&arg, "--sparse-block=%lu", sparse_files_block_size) < 0)
 |  | ||||||
| +			goto oom;
 |  | ||||||
| +		args[ac++] = arg;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
|  	if (io_timeout) { |  | ||||||
|  		if (asprintf(&arg, "--timeout=%d", io_timeout) < 0) |  | ||||||
|  			goto oom; |  | ||||||
| diff --git a/rsync.yo b/rsync.yo
 |  | ||||||
| --- a/rsync.yo
 |  | ||||||
| +++ b/rsync.yo
 |  | ||||||
| @@ -377,6 +377,7 @@ to the detailed description below for a complete description.  verb(
 |  | ||||||
|       --super                 receiver attempts super-user activities |  | ||||||
|       --fake-super            store/recover privileged attrs using xattrs |  | ||||||
|   -S, --sparse                turn sequences of nulls into sparse blocks |  | ||||||
| +     --sparse-block=SIZE     set block size used to handle sparse files
 |  | ||||||
|       --preallocate           allocate dest files before writing |  | ||||||
|   -n, --dry-run               perform a trial run with no changes made |  | ||||||
|   -W, --whole-file            copy files whole (w/o delta-xfer algorithm) |  | ||||||
| @@ -1299,6 +1300,15 @@ If combined with bf(--sparse), the file will only have sparse blocks (as
 |  | ||||||
|  opposed to allocated sequences of null bytes) if the kernel version and |  | ||||||
|  filesystem type support creating holes in the allocated data. |  | ||||||
| 
 |  | ||||||
| +dit(bf(--sparse-block=SIZE)) Change the block size used to handle sparse files
 |  | ||||||
| +to SIZE bytes.  This option only has an effect if the bf(--sparse) (bf(-S))
 |  | ||||||
| +option was also specified.  The default block size used by rsync to detect a
 |  | ||||||
| +file hole is 1024 bytes; when the receiver writes data to the destination file
 |  | ||||||
| +and option bf(--sparse) is used, rsync checks every 1024-bytes chunk to detect
 |  | ||||||
| +if they are actually filled with data or not.  With certain filesystems,
 |  | ||||||
| +optimized to receive data streams for example, enlarging this block size can
 |  | ||||||
| +strongly increase performance.  The option can be used to tune this block size.
 |  | ||||||
| +
 |  | ||||||
|  dit(bf(-n, --dry-run)) This makes rsync perform a trial run that doesn't |  | ||||||
|  make any changes (and produces mostly the same output as a real run).  It |  | ||||||
|  is most commonly used in combination with the bf(-v, --verbose) and/or |  | ||||||
| diff --git a/rsync.1 b/rsync.1
 |  | ||||||
| index 855dd47..1d7af3c 100644
 |  | ||||||
| --- a/rsync.1
 |  | ||||||
| +++ b/rsync.1
 |  | ||||||
| @@ -454,6 +454,7 @@ to the detailed description below for a complete description.
 |  | ||||||
|       \-\-super                 receiver attempts super\-user activities |  | ||||||
|       \-\-fake\-super            store/recover privileged attrs using xattrs |  | ||||||
|   \-S, \-\-sparse                turn sequences of nulls into sparse blocks |  | ||||||
| +     \-\-sparse-block=SIZE      set block size used to handle sparse files
 |  | ||||||
|       \-\-preallocate           allocate dest files before writing |  | ||||||
|   \-n, \-\-dry\-run               perform a trial run with no changes made |  | ||||||
|   \-W, \-\-whole\-file            copy files whole (w/o delta\-xfer algorithm) |  | ||||||
| @@ -1493,6 +1493,16 @@ If combined with \fB\-\-sparse\fP, the file will only have sparse blocks (as
 |  | ||||||
|  opposed to allocated sequences of null bytes) if the kernel version and |  | ||||||
|  filesystem type support creating holes in the allocated data. |  | ||||||
|  .IP  |  | ||||||
| +.IP "\fB\-\-sparse\-block=SIZE\fP"
 |  | ||||||
| +Change the block size used to handle sparse files
 |  | ||||||
| +to SIZE bytes.  This option only has an effect if the \fB\-\-sparse\fP (\fB\-S\fP)
 |  | ||||||
| +option was also specified.  The default block size used by rsync to detect a
 |  | ||||||
| +file hole is 1024 bytes; when the receiver writes data to the destination file
 |  | ||||||
| +and option \fB\-\-sparse\fP is used, rsync checks every 1024\-bytes chunk to detect
 |  | ||||||
| +if they are actually filled with data or not.  With certain filesystems,
 |  | ||||||
| +optimized to receive data streams for example, enlarging this block size can
 |  | ||||||
| +strongly increase performance.  The option can be used to tune this block size.
 |  | ||||||
| +.IP
 |  | ||||||
|  .IP "\fB\-n, \-\-dry\-run\fP" |  | ||||||
|  This makes rsync perform a trial run that doesn\(cq\&t |  | ||||||
|  make any changes (and produces mostly the same output as a real run).  It |  | ||||||
| @ -1,218 +0,0 @@ | |||||||
| diff --git a/exclude.c b/exclude.c
 |  | ||||||
| index d36a105e..da25661b 100644
 |  | ||||||
| --- a/exclude.c
 |  | ||||||
| +++ b/exclude.c
 |  | ||||||
| @@ -33,18 +33,15 @@ extern int recurse;
 |  | ||||||
|  extern int local_server; |  | ||||||
|  extern int prune_empty_dirs; |  | ||||||
|  extern int ignore_perishable; |  | ||||||
| -extern int old_style_args;
 |  | ||||||
|  extern int relative_paths; |  | ||||||
|  extern int delete_mode; |  | ||||||
|  extern int delete_excluded; |  | ||||||
|  extern int cvs_exclude; |  | ||||||
|  extern int sanitize_paths; |  | ||||||
|  extern int protocol_version; |  | ||||||
| -extern int read_batch;
 |  | ||||||
| -extern int list_only;
 |  | ||||||
| +extern int trust_sender_args;
 |  | ||||||
|  extern int module_id; |  | ||||||
|   |  | ||||||
| -extern char *filesfrom_host;
 |  | ||||||
|  extern char curr_dir[MAXPATHLEN]; |  | ||||||
|  extern unsigned int curr_dir_len; |  | ||||||
|  extern unsigned int module_dirlen; |  | ||||||
| @@ -55,6 +52,7 @@ filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" };
 |  | ||||||
|  filter_rule_list implied_filter_list = { .debug_type = " [implied]" }; |  | ||||||
|   |  | ||||||
|  int saw_xattr_filter = 0; |  | ||||||
| +int trust_sender_args = 0;
 |  | ||||||
|  int trust_sender_filter = 0; |  | ||||||
|   |  | ||||||
|  /* Need room enough for ":MODS " prefix plus some room to grow. */ |  | ||||||
| @@ -377,7 +375,7 @@ void add_implied_include(const char *arg, int skip_daemon_module)
 |  | ||||||
|  	int slash_cnt = 0; |  | ||||||
|  	const char *cp; |  | ||||||
|  	char *p; |  | ||||||
| -	if (am_server || old_style_args || list_only || read_batch || filesfrom_host != NULL)
 |  | ||||||
| +	if (trust_sender_args)
 |  | ||||||
|  		return; |  | ||||||
|  	if (partial_string_len) { |  | ||||||
|  		arg_len = strlen(arg); |  | ||||||
| diff --git a/main.c b/main.c
 |  | ||||||
| index 6721ceb7..9ebfbea7 100644
 |  | ||||||
| --- a/main.c
 |  | ||||||
| +++ b/main.c
 |  | ||||||
| @@ -89,7 +89,6 @@ extern int backup_dir_len;
 |  | ||||||
|  extern BOOL shutting_down; |  | ||||||
|  extern int backup_dir_len; |  | ||||||
|  extern int basis_dir_cnt; |  | ||||||
| -extern int trust_sender_filter;
 |  | ||||||
|  extern struct stats stats; |  | ||||||
|  extern char *stdout_format; |  | ||||||
|  extern char *logfile_format; |  | ||||||
| @@ -636,7 +635,6 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
 |  | ||||||
|  #ifdef ICONV_CONST |  | ||||||
|  		setup_iconv(); |  | ||||||
|  #endif |  | ||||||
| -		trust_sender_filter = 1;
 |  | ||||||
|  	} else if (local_server) { |  | ||||||
|  		/* If the user didn't request --[no-]whole-file, force |  | ||||||
|  		 * it on, but only if we're not batch processing. */ |  | ||||||
| diff --git a/options.c b/options.c
 |  | ||||||
| index e7a9fcae..4feeb7e0 100644
 |  | ||||||
| --- a/options.c
 |  | ||||||
| +++ b/options.c
 |  | ||||||
| @@ -27,6 +27,8 @@
 |  | ||||||
|  extern int local_server; |  | ||||||
|  extern int sanitize_paths; |  | ||||||
|  extern int daemon_over_rsh; |  | ||||||
| +extern int trust_sender_args;
 |  | ||||||
| +extern int trust_sender_filter;
 |  | ||||||
|  extern unsigned int module_dirlen; |  | ||||||
|  extern filter_rule_list filter_list; |  | ||||||
|  extern filter_rule_list daemon_filter_list; |  | ||||||
| @@ -64,6 +66,7 @@ int preserve_atimes = 0;
 |  | ||||||
|  static int daemon_opt;   /* sets am_daemon after option error-reporting */ |  | ||||||
|  static int omit_dir_times = 0; |  | ||||||
|  static int omit_link_times = 0; |  | ||||||
| +int trust_sender = 0;
 |  | ||||||
|  static int F_option_cnt = 0; |  | ||||||
|  static int modify_window_set; |  | ||||||
|  static int itemize_changes = 0; |  | ||||||
| @@ -788,6 +791,7 @@ static struct poptOption long_options[] = {
 |  | ||||||
|    {"protect-args",    's', POPT_ARG_VAL,    &protect_args, 1, 0, 0}, |  | ||||||
|    {"no-protect-args",  0,  POPT_ARG_VAL,    &protect_args, 0, 0, 0}, |  | ||||||
|    {"no-s",             0,  POPT_ARG_VAL,    &protect_args, 0, 0, 0}, |  | ||||||
| +  {"trust-sender",     0,  POPT_ARG_VAL,    &trust_sender, 1, 0, 0},
 |  | ||||||
|    {"numeric-ids",      0,  POPT_ARG_VAL,    &numeric_ids, 1, 0, 0 }, |  | ||||||
|    {"no-numeric-ids",   0,  POPT_ARG_VAL,    &numeric_ids, 0, 0, 0 }, |  | ||||||
|    {"usermap",          0,  POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 }, |  | ||||||
| @@ -2465,6 +2469,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
 |  | ||||||
|  		} |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| +	if (trust_sender || am_server || read_batch)
 |  | ||||||
| +		trust_sender_args = trust_sender_filter = 1;
 |  | ||||||
| +	else if (old_style_args || filesfrom_host != NULL)
 |  | ||||||
| +		trust_sender_args = 1;
 |  | ||||||
| +
 |  | ||||||
|  	am_starting_up = 0; |  | ||||||
|   |  | ||||||
|  	return 1; |  | ||||||
| @@ -2438,9 +2438,7 @@ char *safe_arg(const char *opt, const char *arg)
 |  | ||||||
|  	char *ret; |  | ||||||
|  	if (!protect_args && old_style_args < 2 && (!old_style_args || (!is_filename_arg && opt != SPLIT_ARG_WHEN_OLD))) { |  | ||||||
|  		const char *f; |  | ||||||
| -		if (!old_style_args && *arg == '~' 
 |  | ||||||
| -				&& ((relative_paths && !strstr(arg, "/./")) 
 |  | ||||||
| -				|| !strchr(arg, '/'))) {
 |  | ||||||
| +		if (!trust_sender_args && *arg == '~' && (relative_paths || !strchr(arg, '/'))) {
 |  | ||||||
|  			extras++; |  | ||||||
|  			escape_leading_tilde = 1; |  | ||||||
|  		} |  | ||||||
| diff --git a/rsync.1.old b/rsync.1
 |  | ||||||
| index 839f5ad..6882cf5 100644
 |  | ||||||
| --- a/rsync.1.old
 |  | ||||||
| +++ b/rsync.1
 |  | ||||||
| @@ -182,9 +182,39 @@ particular rsync daemon by leaving off the module name:
 |  | ||||||
|  \f(CWrsync somehost.mydomain.com::\fP |  | ||||||
|  .RE |  | ||||||
|   |  | ||||||
| -.PP 
 |  | ||||||
| -See the following section for more details.
 |  | ||||||
| -.PP 
 |  | ||||||
| +.SH "MULTI-HOST SECURITY"
 |  | ||||||
| +
 |  | ||||||
| +.PP
 |  | ||||||
| +Rsync takes steps to ensure that the file requests that are shared in a
 |  | ||||||
| +transfer are protected against various security issues.  Most of the potential
 |  | ||||||
| +problems arise on the receiving side where rsync takes steps to ensure that the
 |  | ||||||
| +list of files being transferred remains within the bounds of what was
 |  | ||||||
| +requested.
 |  | ||||||
| +.PP
 |  | ||||||
| +Toward this end, rsync 3.1.2 and later have aborted when a file list contains
 |  | ||||||
| +an absolute or relative path that tries to escape out of the top of the
 |  | ||||||
| +transfer.  Also, beginning with version 3.2.5, rsync does two more safety
 |  | ||||||
| +checks of the file list to (1) ensure that no extra source arguments were added
 |  | ||||||
| +into the transfer other than those that the client requested and (2) ensure
 |  | ||||||
| +that the file list obeys the exclude rules that we sent to the sender.
 |  | ||||||
| +.PP
 |  | ||||||
| +For those that don't yet have a 3.2.5 client rsync, it is safest to do a copy
 |  | ||||||
| +into a dedicated destination directory for the remote files rather than
 |  | ||||||
| +requesting the remote content get mixed in with other local content.  For
 |  | ||||||
| +example, doing an rsync copy into your home directory is potentially unsafe on
 |  | ||||||
| +an older rsync if the remote rsync is being controlled by a bad actor:
 |  | ||||||
| +.PP
 |  | ||||||
| +.RS
 |  | ||||||
| +\f(CWrsync \-aiv host:dir1 ~\fP
 |  | ||||||
| +.RE
 |  | ||||||
| +.PP
 |  | ||||||
| +A safer command would be:
 |  | ||||||
| +.RS
 |  | ||||||
| +\f(CWrsync \-aiv host:dir1 ~/host-files\fP
 |  | ||||||
| +.RE
 |  | ||||||
| +.PP
 |  | ||||||
| +See the \fB\-\-trust\-sender\fP option for additional details.
 |  | ||||||
| +
 |  | ||||||
|  .SH "ADVANCED USAGE" |  | ||||||
|   |  | ||||||
|  .PP  |  | ||||||
| @@ -519,6 +549,7 @@ to the detailed description below for a complete description.
 |  | ||||||
|   \-0, \-\-from0                 all *from/filter files are delimited by 0s |  | ||||||
|       \-\-old\-args              disable the modern arg-protection idiom |  | ||||||
|   \-s, \-\-protect\-args          no space\-splitting; wildcard chars only |  | ||||||
| +     \-\-trust\-sender          trust the remote sender's file list
 |  | ||||||
|       \-\-address=ADDRESS       bind address for outgoing socket to daemon |  | ||||||
|       \-\-port=PORT             specify double\-colon alternate port number |  | ||||||
|       \-\-sockopts=OPTIONS      specify custom TCP options |  | ||||||
| @@ -2119,6 +2150,49 @@ This option conflicts with the \fB\-\-old\-args\fP option.
 |  | ||||||
|  Note that this option is incompatible with the use of the restricted rsync |  | ||||||
|  script (`rrsync`) since it hides options from the script's inspection. |  | ||||||
|  .IP |  | ||||||
| +.IP "\fB\-\-trust\-sender\fP"
 |  | ||||||
| +This option disables two extra validation checks that a local client
 |  | ||||||
| +performs on the file list generated by a remote sender.  This option should
 |  | ||||||
| +only be used if you trust the sender to not put something malicious in the
 |  | ||||||
| +file list (something that could possibly be done via a modified rsync, a
 |  | ||||||
| +modified shell, or some other similar manipulation).
 |  | ||||||
| +.IP
 |  | ||||||
| +Normally, the rsync client (as of version 3.2.5) runs two extra validation
 |  | ||||||
| +checks when pulling files from a remote rsync:
 |  | ||||||
| +.RS
 |  | ||||||
| +.IP o
 |  | ||||||
| +It verifies that additional arg items didn't get added at the top of the
 |  | ||||||
| +transfer.
 |  | ||||||
| +.IP o
 |  | ||||||
| +It verifies that none of the items in the file list are names that should
 |  | ||||||
| +have been excluded (if filter rules were specified).
 |  | ||||||
| +.RE
 |  | ||||||
| +.IP
 |  | ||||||
| +Note that various options can turn off one or both of these checks if the
 |  | ||||||
| +option interferes with the validation.  For instance:
 |  | ||||||
| +.RS
 |  | ||||||
| +.IP o
 |  | ||||||
| +Using a per-directory filter file reads filter rules that only the server
 |  | ||||||
| +knows about, so the filter checking is disabled.
 |  | ||||||
| +.IP o
 |  | ||||||
| +Using the \fB\-\-old\-args\fP option allows the sender to manipulate the
 |  | ||||||
| +requested args, so the arg checking is disabled.
 |  | ||||||
| +.IP o
 |  | ||||||
| +Reading the files-from list from the server side means that the client
 |  | ||||||
| +doesn't know the arg list, so the arg checking is disabled.
 |  | ||||||
| +.IP o
 |  | ||||||
| +Using \fB\-\-read\-batch\fP disables both checks since the batch file's
 |  | ||||||
| +contents will have been verified when it was created.
 |  | ||||||
| +.RE
 |  | ||||||
| +.IP
 |  | ||||||
| +This option may help an under-powered client server if the extra pattern
 |  | ||||||
| +matching is slowing things down on a huge transfer.  It can also be used
 |  | ||||||
| +work around a currently-unknown bug in the verification logic for a transfer
 |  | ||||||
| +from a trusted sender.
 |  | ||||||
| +.IP
 |  | ||||||
| +When using this option it is a good idea to specify a dedicated destination
 |  | ||||||
| +directory, as discussed in the \(dq\&MULTI-HOST SECURITY\(dq\& section.
 |  | ||||||
| +.IP
 |  | ||||||
|  .IP "\fB\-T, \-\-temp\-dir=DIR\fP" |  | ||||||
|  This option instructs rsync to use DIR as a |  | ||||||
|  scratch directory when creating temporary copies of the files transferred |  | ||||||
| @ -1,38 +0,0 @@ | |||||||
| diff --git a/xattrs.c b/xattrs.c
 |  | ||||||
| index 508649c0..3c549192 100644
 |  | ||||||
| --- a/xattrs.c
 |  | ||||||
| +++ b/xattrs.c
 |  | ||||||
| @@ -1055,7 +1055,7 @@ int set_xattr(const char *fname, const struct file_struct *file, const char *fna
 |  | ||||||
|  { |  | ||||||
|  	rsync_xa_list *glst = rsync_xal_l.items; |  | ||||||
|  	item_list *lst; |  | ||||||
| -	int ndx;
 |  | ||||||
| +	int ndx, added_write_perm = 0;
 |  | ||||||
|   |  | ||||||
|  	if (dry_run) |  | ||||||
|  		return 1; /* FIXME: --dry-run needs to compute this value */ |  | ||||||
| @@ -1084,10 +1084,23 @@ int set_xattr(const char *fname, const struct file_struct *file, const char *fna
 |  | ||||||
|  	} |  | ||||||
|  #endif |  | ||||||
|   |  | ||||||
| +	/* If the target file lacks write permission, we try to add it
 |  | ||||||
| +	 * temporarily so we can change the extended attributes. */
 |  | ||||||
| +	if (!am_root
 |  | ||||||
| +#ifdef SUPPORT_LINKS
 |  | ||||||
| +	 && !S_ISLNK(sxp->st.st_mode)
 |  | ||||||
| +#endif
 |  | ||||||
| +	 && access(fname, W_OK) < 0
 |  | ||||||
| +	 && do_chmod(fname, (sxp->st.st_mode & CHMOD_BITS) | S_IWUSR) == 0)
 |  | ||||||
| +		added_write_perm = 1;
 |  | ||||||
| +
 |  | ||||||
|  	ndx = F_XATTR(file); |  | ||||||
|  	glst += ndx; |  | ||||||
|  	lst = &glst->xa_items; |  | ||||||
| -	return rsync_xal_set(fname, lst, fnamecmp, sxp);
 |  | ||||||
| +	int return_value = rsync_xal_set(fname, lst, fnamecmp, sxp);
 |  | ||||||
| +	if (added_write_perm) /* remove the temporary write permission */
 |  | ||||||
| +		do_chmod(fname, sxp->st.st_mode);
 |  | ||||||
| +	return return_value;
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  #ifdef SUPPORT_ACLS |  | ||||||
							
								
								
									
										11
									
								
								SOURCES/rsync-3.2.2-runtests.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								SOURCES/rsync-3.2.2-runtests.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | diff --git a/runtests.sh b/runtests.sh
 | ||||||
|  | index 0c463be..eecf530 100755
 | ||||||
|  | --- a/runtests.sh
 | ||||||
|  | +++ b/runtests.sh
 | ||||||
|  | @@ -280,6 +280,7 @@ for testscript in $suitedir/$whichtests; do
 | ||||||
|  | 
 | ||||||
|  |      case "$testscript" in | ||||||
|  |      *hardlinks*) TESTRUN_TIMEOUT=600 ;; | ||||||
|  | +    *default-acls*) continue ;;
 | ||||||
|  |      *) TESTRUN_TIMEOUT=300 ;; | ||||||
|  |      esac | ||||||
| @ -1,10 +0,0 @@ | |||||||
| --- rsync-3.0.9/rsync.1   2011-09-23 18:42:26.000000000 +0200
 |  | ||||||
| +++ rsync-3.0.9/rsync.1   2012-09-19 10:40:19.698802861 +0200
 |  | ||||||
| @@ -445,6 +445,7 @@
 |  | ||||||
|   \-o, \-\-owner                 preserve owner (super\-user only) |  | ||||||
|   \-g, \-\-group                 preserve group |  | ||||||
|       \-\-devices               preserve device files (super\-user only) |  | ||||||
| +     \-\-copy-devices          copy device contents as regular file
 |  | ||||||
|       \-\-specials              preserve special files |  | ||||||
|   \-D                          same as \-\-devices \-\-specials |  | ||||||
|   \-t, \-\-times                 preserve modification times |  | ||||||
							
								
								
									
										274
									
								
								SPECS/rsync.spec
									
									
									
									
									
								
							
							
						
						
									
										274
									
								
								SPECS/rsync.spec
									
									
									
									
									
								
							| @ -3,15 +3,14 @@ | |||||||
| %define isprerelease 0 | %define isprerelease 0 | ||||||
| 
 | 
 | ||||||
| %if %isprerelease | %if %isprerelease | ||||||
| %define prerelease pre1 | %define prerelease pre3 | ||||||
| %endif | %endif | ||||||
| 
 | 
 | ||||||
| Summary: A program for synchronizing files over a network | Summary: A program for synchronizing files over a network | ||||||
| Name: rsync | Name: rsync | ||||||
| Version: 3.1.3 | Version: 3.4.0 | ||||||
| Release: 23%{?dist} | Release: 1%{?prerelease}%{?dist} | ||||||
| Group: Applications/Internet | URL: https://rsync.samba.org/ | ||||||
| URL: http://rsync.samba.org/ |  | ||||||
| 
 | 
 | ||||||
| Source0: https://download.samba.org/pub/rsync/src/rsync-%{version}%{?prerelease}.tar.gz | Source0: https://download.samba.org/pub/rsync/src/rsync-%{version}%{?prerelease}.tar.gz | ||||||
| Source1: https://download.samba.org/pub/rsync/src/rsync-patches-%{version}%{?prerelease}.tar.gz | Source1: https://download.samba.org/pub/rsync/src/rsync-patches-%{version}%{?prerelease}.tar.gz | ||||||
| @ -21,34 +20,27 @@ Source4: rsyncd.conf | |||||||
| Source5: rsyncd.sysconfig | Source5: rsyncd.sysconfig | ||||||
| Source6: rsyncd@.service | Source6: rsyncd@.service | ||||||
| 
 | 
 | ||||||
| BuildRequires: libacl-devel, libattr-devel, autoconf, popt-devel, systemd | BuildRequires: make | ||||||
| #Requires: zlib | BuildRequires: gcc | ||||||
|  | BuildRequires: gcc-c++ | ||||||
|  | BuildRequires: libacl-devel | ||||||
|  | BuildRequires: libattr-devel | ||||||
|  | BuildRequires: autoconf | ||||||
|  | BuildRequires: popt-devel | ||||||
|  | BuildRequires: systemd | ||||||
|  | BuildRequires: lz4-devel | ||||||
|  | BuildRequires: openssl-devel | ||||||
|  | BuildRequires: libzstd-devel | ||||||
|  | BuildRequires: xxhash-devel | ||||||
| #Added virtual provide for zlib due to https://fedoraproject.org/wiki/Bundled_Libraries?rd=Packaging:Bundled_Libraries | #Added virtual provide for zlib due to https://fedoraproject.org/wiki/Bundled_Libraries?rd=Packaging:Bundled_Libraries | ||||||
| Provides: bundled(zlib) = 1.2.8 | Provides: bundled(zlib) = 1.2.8 | ||||||
| License: GPLv3+ | #rsync code is distributed under GPLv3+ license. There are files under popt/ directory | ||||||
|  | #which are provided under X11 license but they are not compiled. Except rsync links to | ||||||
|  | #popt provided by popt-devel from the system. Should this change, X11 license should be  | ||||||
|  | #mentioned here as well. | ||||||
|  | License: GPL-3.0-or-later | ||||||
| 
 | 
 | ||||||
| Patch0: rsync-man.patch | Patch0: rsync-3.2.2-runtests.patch | ||||||
| Patch1: rsync-3.0.6-iconv-logging.patch |  | ||||||
| Patch2: rsync-3.1.3-covscan.patch |  | ||||||
| Patch3: rsync-3.1.2-remove-symlinks.patch |  | ||||||
| Patch4: rsync-3.1.2-vvv-hang.patch |  | ||||||
| Patch5: rsync-3.1.3-ignore-missing.patch |  | ||||||
| Patch6: rsync-3.1.3-append-check.patch |  | ||||||
| Patch7: rsync-3.1.3-skip-compress.patch |  | ||||||
| Patch8: rsync-3.1.3-xattr.patch |  | ||||||
| Patch9: rsync-3.1.3-cve-2018-25032.patch |  | ||||||
| Patch10: rsync-3.1.3-sparse-block.patch |  | ||||||
| Patch11: rsync-3.1.3-cve-2022-29154.patch |  | ||||||
| Patch12: rsync-3.1.3-cve-2022-37434.patch |  | ||||||
| Patch13: rsync-3.1.3-filtering-rules.patch |  | ||||||
| Patch14: rsync-3.1.3-missing-xattr-filter.patch |  | ||||||
| Patch15: rsync-3.1.3-cve-2024-12085.patch |  | ||||||
| Patch16: rsync-3.1.3-cve-2024-12087.patch |  | ||||||
| Patch17: rsync-3.1.3-cve-2024-12088.patch |  | ||||||
| Patch18: rsync-3.1.3-cve-2024-12747.patch |  | ||||||
| # a fix for CVE-2016-9840 in zlib but marked as CVE-2025-4638 for a different component |  | ||||||
| Patch19: rsync-3.1.3-cve-2025-4638.patch |  | ||||||
| Patch20: rsync-3.1.3-trust-sender.patch |  | ||||||
| 
 | 
 | ||||||
| %description | %description | ||||||
| Rsync uses a reliable algorithm to bring remote and host files into | Rsync uses a reliable algorithm to bring remote and host files into | ||||||
| @ -72,50 +64,27 @@ package provides the anonymous rsync service. | |||||||
| # TAG: for pre versions use | # TAG: for pre versions use | ||||||
| 
 | 
 | ||||||
| %if %isprerelease | %if %isprerelease | ||||||
| %setup -q -n rsync-%{version}%{?prerelease} | %autosetup -n rsync-%{version}%{?prerelease} -p1 | ||||||
| %setup -q -b 1 -n rsync-%{version}%{?prerelease} |  | ||||||
| %else | %else | ||||||
| %setup -q | %autosetup -p1 | ||||||
| %setup -q -b 1 |  | ||||||
| %endif | %endif | ||||||
| 
 | 
 | ||||||
| #Needed for compatibility with previous patched rsync versions |  | ||||||
| patch -p1 -i patches/acls.diff |  | ||||||
| patch -p1 -i patches/xattrs.diff |  | ||||||
| 
 |  | ||||||
| #Enable --copy-devices parameter |  | ||||||
| patch -p1 -i patches/copy-devices.diff |  | ||||||
| 
 |  | ||||||
| %patch0 -p1 -b .man |  | ||||||
| %patch1 -p1 -b .iconv |  | ||||||
| %patch2 -p1 -b .covscan |  | ||||||
| %patch3 -p1 -b .symlinks |  | ||||||
| %patch4 -p1 -b .vvv |  | ||||||
| %patch5 -p1 -b .missing |  | ||||||
| %patch6 -p1 -b .append |  | ||||||
| %patch7 -p1 -b .skip-compress |  | ||||||
| %patch8 -p1 -b .xattr |  | ||||||
| %patch9 -p1 -b .cve-2018-25032 |  | ||||||
| %patch10 -p1 -b .spars-block |  | ||||||
| %patch11 -p1 -b .cve-2022-29154 |  | ||||||
| %patch12 -p1 -b .cve-2022-37434 |  | ||||||
| %patch13 -p1 -b .filtering-rules |  | ||||||
| %patch14 -p1 -b .xattr-filter |  | ||||||
| %patch15 -p1 -b .cve-2024-12085 |  | ||||||
| %patch16 -p1 -b .cve-2024-12087 |  | ||||||
| %patch17 -p1 -b .cve-2024-12088 |  | ||||||
| %patch18 -p1 -b .cve-2024-12747 |  | ||||||
| %patch19 -p1 -b .cve-2025-4638 |  | ||||||
| %patch20 -p1 -b .trust-sender |  | ||||||
| 
 |  | ||||||
| %build | %build | ||||||
| %configure | %configure \ | ||||||
| # --with-included-zlib=no temporary disabled because of #1043965 |   --enable-openssl \ | ||||||
|  |   --enable-xxhash \ | ||||||
|  |   --enable-zstd \ | ||||||
|  |   --enable-lz4 \ | ||||||
|  |   --enable-ipv6 | ||||||
| 
 | 
 | ||||||
| make %{?_smp_mflags} | %{make_build} | ||||||
|  | 
 | ||||||
|  | %check | ||||||
|  | make check | ||||||
|  | chmod -x support/* | ||||||
| 
 | 
 | ||||||
| %install | %install | ||||||
| %makeinstall INSTALLCMD='install -p' INSTALLMAN='install -p' | %{make_install} INSTALLCMD='install -p' INSTALLMAN='install -p' | ||||||
| 
 | 
 | ||||||
| install -D -m644 %{SOURCE3} $RPM_BUILD_ROOT/%{_unitdir}/rsyncd.service | install -D -m644 %{SOURCE3} $RPM_BUILD_ROOT/%{_unitdir}/rsyncd.service | ||||||
| install -D -m644 %{SOURCE2} $RPM_BUILD_ROOT/%{_unitdir}/rsyncd.socket | install -D -m644 %{SOURCE2} $RPM_BUILD_ROOT/%{_unitdir}/rsyncd.socket | ||||||
| @ -123,21 +92,17 @@ install -D -m644 %{SOURCE4} $RPM_BUILD_ROOT/%{_sysconfdir}/rsyncd.conf | |||||||
| install -D -m644 %{SOURCE5} $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/rsyncd | install -D -m644 %{SOURCE5} $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/rsyncd | ||||||
| install -D -m644 %{SOURCE6} $RPM_BUILD_ROOT/%{_unitdir}/rsyncd@.service | install -D -m644 %{SOURCE6} $RPM_BUILD_ROOT/%{_unitdir}/rsyncd@.service | ||||||
| 
 | 
 | ||||||
| %check |  | ||||||
| make check |  | ||||||
| #scripts in support/* are needed to run upstream tests but after install these should not be executable |  | ||||||
| chmod -x support/* |  | ||||||
| 
 |  | ||||||
| %files | %files | ||||||
| %{!?_licensedir:%global license %%doc} |  | ||||||
| %license COPYING | %license COPYING | ||||||
| %doc NEWS OLDNEWS README support/ tech_report.tex | %doc support/ tech_report.tex | ||||||
| %{_bindir}/%{name} | %{_bindir}/%{name} | ||||||
|  | %{_bindir}/%{name}-ssl | ||||||
| %{_mandir}/man1/%{name}.1* | %{_mandir}/man1/%{name}.1* | ||||||
| 
 | %{_mandir}/man1/%{name}-ssl.1* | ||||||
| %files daemon |  | ||||||
| %{_mandir}/man5/rsyncd.conf.5* | %{_mandir}/man5/rsyncd.conf.5* | ||||||
| %config(noreplace) %{_sysconfdir}/rsyncd.conf | %config(noreplace) %{_sysconfdir}/rsyncd.conf | ||||||
|  | 
 | ||||||
|  | %files daemon | ||||||
| %config(noreplace) %{_sysconfdir}/sysconfig/rsyncd | %config(noreplace) %{_sysconfdir}/sysconfig/rsyncd | ||||||
| %{_unitdir}/rsyncd.socket | %{_unitdir}/rsyncd.socket | ||||||
| %{_unitdir}/rsyncd.service | %{_unitdir}/rsyncd.service | ||||||
| @ -153,72 +118,137 @@ chmod -x support/* | |||||||
| %systemd_postun_with_restart rsyncd.service | %systemd_postun_with_restart rsyncd.service | ||||||
| 
 | 
 | ||||||
| %changelog | %changelog | ||||||
| * Wed May 28 2025 Michal Ruprich <mruprich@redhat.com> - 3.1.3-23 | * Tue Jan 14 2025 Jonathan Wright <jonathan@almalinux.org> - 3.4.0-1 | ||||||
| - Resolves: RHEL-52004 - Slowness in rsync due to extra validation steps | - Update to 3.4.0 | ||||||
|  | - Fix for CVE-2024-12084 | ||||||
|  | - Fix for CVE-2024-12085 | ||||||
|  | - Fix for CVE-2024-12086 | ||||||
|  | - Fix for CVE-2024-12087 | ||||||
|  | - Fix for CVE-2024-12088 | ||||||
|  | - Fix for CVE-2024-12747 | ||||||
| 
 | 
 | ||||||
| * Mon May 26 2025 Michal Ruprich <mruprich@redhat.com> - 3.1.3-22 | * Wed Apr 17 2024 Andrew Lukoshko <alukoshko@almalinux.org> - 3.3.0-1 | ||||||
| - Resolves: RHEL-91519 - Improper Pointer Arithmetic in pcl | - New version 3.3.0 | ||||||
| 
 | 
 | ||||||
| * Tue Feb 04 2025 Michal Ruprich <mruprich@redhat.com> - 3.1.3-21 | * Mon Mar 20 2023 Michal Ruprich <mruprich@redhat.com> - 3.2.7-3 | ||||||
| - Resolves: RHEL-70207 - Path traversal vulnerability in rsync | - SPDX migration | ||||||
| 
 | 
 | ||||||
| * Mon Feb 03 2025 Michal Ruprich <mruprich@redhat.com> - 3.1.3-20 | * Fri Jan 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.2.7-2 | ||||||
| - Resolves: RHEL-70207 - Path traversal vulnerability in rsync | - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild | ||||||
| - Resolves: RHEL-70209 - --safe-links option bypass leads to path traversal |  | ||||||
| - Resolves: RHEL-72502 - Race Condition in rsync Handling Symbolic Links |  | ||||||
| - Resolves: RHEL-70157 - Info Leak via Uninitialized Stack Contents |  | ||||||
| 
 | 
 | ||||||
| * Wed Nov 02 2022 Michal Ruprich <mruprich@redhat.com> - 3.1.3-19.1 | * Fri Oct 21 2022 Michal Ruprich <mruprich@redhat.com> - 3.2.7-1 | ||||||
| - Resolves: #2139118 - rsync-daemon fail on 3.1.3 | - New version 3.2.7 | ||||||
| 
 | 
 | ||||||
| * Thu Aug 18 2022 Michal Ruprich <mruprich@redhat.com> - 3.1.3-19 | * Tue Sep 27 2022 Michal Ruprich <mruprich@redhat.com> - 3.2.6-2 | ||||||
| - Resolves: #2116668 - zlib: a heap-based buffer over-read or buffer overflow in inflate in inflate.c via a large gzip header extra field | - Resolves: #2128682 - rsync fail with "ERROR: rejecting unrequested file-list name..." depend of parameters order | ||||||
| 
 | 
 | ||||||
| * Mon Aug 15 2022 Michal Ruprich <mruprich@redhat.com> - 3.1.3-18 | * Mon Sep 12 2022 Michal Ruprich <mruprich@redhat.com> - 3.2.6-1 | ||||||
| - Resolves: #2111175 - remote arbitrary files write inside the directories of connecting peers | - New version 3.2.6 | ||||||
| 
 | 
 | ||||||
| * Mon Aug 08 2022 Michal Ruprich <mruprich@redhat.com> - 3.1.3-17 | * Tue Aug 16 2022 Michal Ruprich <mruprich@redhat.com> - 3.2.5-1 | ||||||
| - Related: #2043753 - New option should not be sent to the server every time | - New version 3.2.5 | ||||||
|  | - Resolves: #2115430 - remote arbitrary files write inside the directories of connecting peers | ||||||
|  | - Fix for CVE-2022-37434 | ||||||
| 
 | 
 | ||||||
| * Thu Jul 28 2022 Michal Ruprich <mruprich@redhat.com> - 3.1.3-16 | * Sat Jul 23 2022 Fedora Release Engineering <releng@fedoraproject.org> - 3.2.4-5 | ||||||
| - Resolves: #2043753 - [RFE] Improve defaults for sparse file buffering | - Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild | ||||||
| 
 | 
 | ||||||
| * Tue Apr 12 2022 Michal Ruprich <mruprich@redhat.com> - 3.1.3-15 | * Tue May 17 2022 Adam Williamson <awilliam@redhat.com> - 3.2.4-4 | ||||||
| - Resolves: #2071513 - A flaw in zlib-1.2.11 when compressing (not decompressing!) certain inputs | - Bump revision to 4 to be higher than wrongly-versioned 3.2.4-3pre3 | ||||||
| 
 | 
 | ||||||
| * Mon Oct 11 2021 Michal Ruprich <mruprich@redhat.com> - 3.1.3-14 | * Tue May 17 2022 Michal Ruprich <mruprich@redhat.com> - 3.2.4-1 | ||||||
| - Related: #1907443 - Adding fmf plans to run tests with tmt | - New version 3.2.4 | ||||||
| 
 | 
 | ||||||
| * Mon Sep 27 2021 Tomas Korbar <tkorbar@redhat.com> - 3.1.3-13 | * Thu Apr 14 2022 Michal Ruprich <mruprich@redhat.com> - 3.2.4-3pre3 | ||||||
| - Resolves: #1907443 - Read-only files that have changed xattrs fail to allow xattr changes | - Fix for CVE-2018-25032 | ||||||
| 
 | 
 | ||||||
| * Fri Dec 18 2020 Michal Ruprich <mruprich@redhat.com> - 3.1.3-12 | * Mon Mar 21 2022 Michal Ruprich <mruprich@redhat.com> - 3.2.4-2pre3 | ||||||
| - Resolves: #1816528 - Defaults for --skip-compress are not working, everything is being compressed | - Removing part of patch that does not belong | ||||||
| 
 | 
 | ||||||
| * Thu Nov 05 2020 Tomas Korbar <tkorbar@redhat.com> - 3.1.3-11 | * Wed Mar 16 2022 Michal Ruprich <mruprich@redhat.com> - 3.2.4-1pre3 | ||||||
| - Resolves: #1855981 - rsync segfaults in --append mode | - New pre-release version 3.2.4pre3 | ||||||
| 
 | 
 | ||||||
| * Thu Nov 05 2020 Tomas Korbar <tkorbar@redhat.com> - 3.1.3-10 | * Fri Jan 21 2022 Fedora Release Engineering <releng@fedoraproject.org> - 3.2.3-14 | ||||||
| - Resolves: #1727093 - rsync: "ABORTING due to invalid path from sender" | - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild | ||||||
| 
 | 
 | ||||||
| * Mon Aug 24 2020 Michal Ruprich <mruprich@redhat.com> - 3.1.3-9 | * Tue Nov 16 2021 Michal Ruprich <mruprich@redhat.com> - 3.2.3-13 | ||||||
| - Resolves: #1667436 - rsyncd.service fails to start at boot if address is configured | - Separating ci tests | ||||||
| 
 | 
 | ||||||
| * Wed Jun 10 2020 Michal Ruprich <mruprich@redhat.com> - 3.1.3-8 | * Tue Nov 16 2021 Michal Ruprich <mruprich@redhat.com> - 3.2.3-12 | ||||||
| - Resolves: #1775561 - rsync 3.1.2 hangs when run with -vvv to sync a large repository | - Disabling STI tests | ||||||
| 
 | 
 | ||||||
| * Tue Oct 29 2019 Michal Ruprich <mruprich@redhat.com> - 3.1.3-7 | * Mon Nov 15 2021 Michal Ruprich <mruprich@redhat.com> - 3.2.3-11 | ||||||
| - Resolves: #1693162 - remove-source-files fails with symlinks | - Bumping version to test fixed gating file | ||||||
| 
 | 
 | ||||||
| * Tue Apr 16 2019 Michal Ruprich <mruprich@redhat.com> - 3.1.3-6 | * Fri Nov  5 2021 Jan Kratochvil <jan@jankratochvil.net> - 3.2.3-10 | ||||||
| - Resolves: #1602683 - Please review important issues found by covscan | - Re-enable xxh128 xxh3 xxh64 disabled during 3.2.2 update. | ||||||
|  | - Enforce openssl xxhash zstd lz4 ipv6 features by --enable-*.  | ||||||
| 
 | 
 | ||||||
| * Tue Apr 16 2019 Michal Ruprich <mruprich@redhat.com> - 3.1.3-5 | * Tue Sep 14 2021 Sahana Prasad <sahana@redhat.com> - 3.2.3-9 | ||||||
| - Resolves: #1656761 - [FJ8.0 Bug]: [REG] The rsync command is terminated with SIGSEGV | - Rebuilt with OpenSSL 3.0.0 | ||||||
| 
 | 
 | ||||||
| * Wed Oct 03 2018 Michal Ruprich <mruprich@redhat.com> - 3.1.3-4 | * Fri Jul 23 2021 Fedora Release Engineering <releng@fedoraproject.org> - 3.2.3-8 | ||||||
| - Resolves: #1635631 - Remove --noatime option from rsync | - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild | ||||||
|   Cleaning spec file | 
 | ||||||
|  | * Sun May 09 2021 Jeff Law <jlaw@tachyum.com> - 3.2.3-7 | ||||||
|  | - Re-enable LTO. | ||||||
|  | 
 | ||||||
|  | * Tue Mar 02 2021 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 3.2.3-6 | ||||||
|  | - Rebuilt for updated systemd-rpm-macros | ||||||
|  |   See https://pagure.io/fesco/issue/2583. | ||||||
|  | 
 | ||||||
|  | * Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 3.2.3-5 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Tue Dec 08 2020 Michal Ruprich <mruprich@redhat.com> - 3.2.3-4 | ||||||
|  | - Resolves: #1894485 - rsync is unable to set permissions when chrooted | ||||||
|  | - Getting rid of deprecated makeinstall macro | ||||||
|  | 
 | ||||||
|  | * Fri Nov 20 2020 Michal Ruprich <mruprich@redhat.com> - 3.2.3-3 | ||||||
|  | - Disabling LTO as a temporary measure for rhbz#1898912 | ||||||
|  | 
 | ||||||
|  | * Thu Nov 19 2020 Michal Ruprich <mruprich@redhat.com> - 3.2.3-2 | ||||||
|  | - Use make macros | ||||||
|  | - https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro | ||||||
|  | 
 | ||||||
|  | * Mon Aug 31 2020 Michal Ruprich <mruprich@redhat.com> - 3.2.3-1 | ||||||
|  | - New version 3.2.3 | ||||||
|  | - Removed upstream patches acls.diff and xattrs.diff | ||||||
|  | 
 | ||||||
|  | * Sat Aug 01 2020 Fedora Release Engineering <releng@fedoraproject.org> - 3.2.2-3 | ||||||
|  | - Second attempt - Rebuilt for | ||||||
|  |   https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 3.2.2-2 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Tue Jul 21 2020 Michal Ruprich <michalruprich@gmail.com> - 3.2.2-1 | ||||||
|  | - New version 3.2.2 | ||||||
|  | 
 | ||||||
|  | * Thu Jan 30 2020 Fedora Release Engineering <releng@fedoraproject.org> - 3.1.3-11 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Thu Oct 10 2019 Michal Ruprich <mruprich@redhat.com> - 3.1.3-10 | ||||||
|  | - Enabling upstream test suite during build rhbz#1533846 | ||||||
|  | 
 | ||||||
|  | * Fri Jul 26 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.1.3-9 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Mon Apr 15 2019 Michal Ruprich <mruprich@redhat.com> - 3.1.3-8 | ||||||
|  | - Resolves: #1452187 - move man page rsyncd.conf(5) from rsync-daemon to rsync package | ||||||
|  | - Moving the config file as well | ||||||
|  | 
 | ||||||
|  | * Tue Mar 19 2019 Michal Ruprich <mruprich@redhat.com> - 3.1.3-7 | ||||||
|  | - Resolves: #1683737 - [abrt] rsync: utf8_internal_loop(): rsync killed by SIGSEGV | ||||||
|  | 
 | ||||||
|  | * Sat Feb 02 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.1.3-6 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Wed Jan 02 2019 Michal Ruprich <mruprich@redhat.com> - 3.1.3-5 | ||||||
|  | - Fix for rhbz#1586346 - rsyncd.service fails to start at boot if address is configured | ||||||
|  | 
 | ||||||
|  | * Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3.1.3-4 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild | ||||||
| 
 | 
 | ||||||
| * Fri Feb 09 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3.1.3-3 | * Fri Feb 09 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3.1.3-3 | ||||||
| - Escape macros in %%changelog | - Escape macros in %%changelog | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user