Package: rsync Version: 2.6.9-2etch2 Severity: normal Tags: patch
Hi.When rsync runs with both --hard-links and --acls, the receiving process can segfault while processing the ACL on any files with a link count > 1. Neither of the (no)acl mount options nor the actual presence of any ACEs seem to make much difference.
It looks like the behavior is due to dereference of an uninitialized portion of a struct statx declared in hard_link_cluster(). Elsewhere in the code, there exist ifdefs to explicitly initialize the extra pointers that extend struct stat when SUPPORT_ACLS is enabled. The bug is similar to one that affected rsync-3.0.3-2 in lenny:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=498083No idea if this will get patched in etch since lenny is tracking rsync3, but some debug info & a simple patch are attached anyway.
Thanks. -R # cat /etc/debian_version ; uname -a 4.0Linux debian 2.6.18-6-686 #1 SMP Fri Dec 12 16:48:28 UTC 2008 i686 GNU/ Linux
# dpkg -s rsync | egrep '^(Version|Depends):' Version: 2.6.9-2etch2Depends: libacl1 (>= 2.2.11-1), libc6 (>= 2.3.6-6), libpopt0 (>= 1.10), lsb-base (>= 3.0)
# dpkg -s libacl1 libc6 libpopt0 lsb-base |egrep '^(Package|Name| Version):'
Package: libacl1 Version: 2.2.41-1 Package: libc6 Version: 2.3.6.ds1-13etch8 Package: libpopt0 Version: 1.10-3 Package: lsb-base Version: 3.1-23.2etch1# for ((i=1;i<=2;i++)) ; do dd if=/dev/zero of=/var/tmp/vol${i} bs=1k count=10240 ; losetup /dev/loop${i} /var/tmp/vol${i} ; mke2fs -j /dev/ loop${i} ; mkdir /mnt/vol${i} ; mount -o defaults,acl /dev/loop${i} / mnt/vol${i} ; done
10240+0 records in 10240+0 records out 10485760 bytes (10 MB) copied, 0.0675322 seconds, 155 MB/s mke2fs 1.40-WIP (14-Nov-2006) Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 2560 inodes, 10240 blocks 512 blocks (5.00%) reserved for the super user First data block=1 Maximum filesystem blocks=10485760 2 block groups 8192 blocks per group, 8192 fragments per group 1280 inodes per group Superblock backups stored on blocks: 8193 Writing inode tables: done Creating journal (1400 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 24 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. 10240+0 records in 10240+0 records out 10485760 bytes (10 MB) copied, 0.0573582 seconds, 183 MB/s mke2fs 1.40-WIP (14-Nov-2006) Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 2560 inodes, 10240 blocks 512 blocks (5.00%) reserved for the super user First data block=1 Maximum filesystem blocks=10485760 2 block groups 8192 blocks per group, 8192 fragments per group 1280 inodes per group Superblock backups stored on blocks: 8193 Writing inode tables: done Creating journal (1400 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 27 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. # mount /dev/hda1 on / type ext3 (rw,errors=remount-ro) tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755) proc on /proc type proc (rw,noexec,nosuid,nodev) sysfs on /sys type sysfs (rw,noexec,nosuid,nodev) udev on /dev type tmpfs (rw,mode=0755) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev) devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620) /dev/hdd on /vicepa type ext3 (rw,errors=remount-ro) AFS on /afs type afs (rw) /dev/hdb on /mnt/gnomehome type reiserfs (rw) /dev/loop1 on /mnt/vol1 type ext3 (rw,acl) /dev/loop2 on /mnt/vol2 type ext3 (rw,acl) # ulimit -c unlimited # mkdir /mnt/vol1/acldir # touch /mnt/vol1/acldir/f{1,2} # ln /mnt/vol1/acldir/{f,l}1 # ln /mnt/vol1/acldir/{f,l}2 # touch /mnt/vol1/acldir/thecheesestandsalone # setfacl -m user:nobody:rwx /mnt/vol1/acldir/f2 # ls -li /mnt/vol1/acldir/ total 2 1282 -rw-r--r-- 2 root root 0 2009-01-28 15:27 f1 1283 -rw-rwxr--+ 2 root root 0 2009-01-28 15:27 f2 1282 -rw-r--r-- 2 root root 0 2009-01-28 15:27 l1 1283 -rw-rwxr--+ 2 root root 0 2009-01-28 15:27 l2 1284 -rw-r--r-- 1 root root 0 2009-01-28 15:27 thecheesestandsalone # rsync --verbose --archive --hard-links --acls /mnt/vol1/ /mnt/vol2/ building file list ... done ./ acldir/ acldir/l1 acldir/l2 acldir/thecheesestandsalone lost+found/rsync: connection unexpectedly closed (96 bytes received so far) [sender] rsync error: error in rsync protocol data stream (code 12) at io.c(453) [sender=2.6.9]
# gdb /usr/bin/rsync /mnt/vol2/core GNU gdb 6.4.90-debian Copyright (C) 2006 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
warning: Can't read pathname for load map: Input/output error. Reading symbols from /lib/libacl.so.1...done. Loaded symbols for /lib/libacl.so.1 Reading symbols from /lib/libpopt.so.0...done. Loaded symbols for /lib/libpopt.so.0 Reading symbols from /lib/tls/i686/cmov/libc.so.6...done. Loaded symbols for /lib/tls/i686/cmov/libc.so.6 Reading symbols from /lib/libattr.so.1...done. Loaded symbols for /lib/libattr.so.1Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/ lib/debug/lib/ld-2.3.6.so...done.
done. Loaded symbols for /lib/ld-linux.so.2 Reading symbols from /lib/tls/i686/cmov/libnss_compat.so.2...done. Loaded symbols for /lib/tls/i686/cmov/libnss_compat.so.2 Reading symbols from /lib/tls/i686/cmov/libnsl.so.1...done. Loaded symbols for /lib/tls/i686/cmov/libnsl.so.1 Reading symbols from /lib/tls/i686/cmov/libnss_nis.so.2...done. Loaded symbols for /lib/tls/i686/cmov/libnss_nis.so.2 Reading symbols from /lib/tls/i686/cmov/libnss_files.so.2...done. Loaded symbols for /lib/tls/i686/cmov/libnss_files.so.2Core was generated by `rsync --verbose --archive --hard-links --acls / mnt/vol1/ /mnt/vol2/'.
Program terminated with signal 11, Segmentation fault. #0 rsync_acl_free (racl=0x2) at acls.c:190 190 if (racl->users.idas) (gdb) ptype racl type = struct rsync_acl { ida_entries users; ida_entries groups; unsigned char user_obj; unsigned char group_obj; unsigned char mask; unsigned char other; } * (gdb) bt #0 rsync_acl_free (racl=0x2) at acls.c:190 #1 0x0806ea56 in free_acl (sxp=0xbf8d2f40) at acls.c:200#2 0x0806925c in hard_link_cluster (file=0xb7d52f08, master=4, itemizing=1, code=FLOG) at hlink.c:323 #3 0x0804bc2a in check_for_finished_hlinks (itemizing=1, code=FLOG) at generator.c:611
#4 0x080689aa in get_redo_num (itemizing=1, code=FLOG) at io.c:393#5 0x0804f225 in generate_files (f_out=1, flist=0x80a2ab0, local_name=0x0) at generator.c:1558 #6 0x080588d1 in do_recv (f_in=0, f_out=1, flist=0x80a2ab0, local_name=0x0) at main.c:764 #7 0x080590fb in start_server (f_in=0, f_out=1, argc=2, argv=0xbf8d41cc) at main.c:871
#8 0x0805a399 in child_main (argc=2, argv=0xbf8d41cc) at main.c:878#9 0x08070868 in local_child (argc=2, argv=0xbf8d41cc, f_in=0xbf8d5200, f_out=0xbf8d51fc,
child_main=0x805a370 <child_main>) at pipe.c:149 #10 0x08059c10 in main (argc=1915617326, argv=0x636e7973) at main.c:438 (gdb) up #1 0x0806ea56 in free_acl (sxp=0xbf8d2f40) at acls.c:200 200 rsync_acl_free(sxp->acc_acl); (gdb) ptype sxp type = struct { struct stat st; struct rsync_acl *acc_acl; struct rsync_acl *def_acl; } * (gdb) print *sxp$1 = {st = {st_dev = 0, __pad1 = 1794, __st_ino = 0, st_mode = 0, st_nlink = 2, st_uid = 16877, st_gid = 2, st_rdev = 3085852609, __pad2 = 0, st_size = 0, st_blksize = 1024, st_blocks = 17592186044416, st_atim = { tv_sec = 2, tv_nsec = 17}, st_mtim = {tv_sec = 1233175523, tv_nsec = 0}, st_ctim = { tv_sec = -1208334636, tv_nsec = 0}, st_ino = 1233175523}, acc_acl = 0x2, def_acl = 0x0}
(gdb) up#2 0x0806925c in hard_link_cluster (file=0xb7d52f08, master=4, itemizing=1, code=FLOG) at hlink.c:323
323 free_acl(&sx); (gdb) list hard_link_cluster 290 #endif 291 292293 void hard_link_cluster(struct file_struct *file, int master, int itemizing,
294 enum logcode code) 295 { 296 #ifdef SUPPORT_HARD_LINKS 297 char hlink1[MAXPATHLEN]; 298 char *hlink2; 299 statx sx; (gdb) 300 STRUCT_STAT st; 301 int statret, ndx = master; 302 303 file->F_HLINDEX = FINISHED_LINK; 304 if (link_stat(f_name(file, hlink1), &st, 0) < 0) 305 return; 306 if (!(file->flags & FLAG_HLINK_TOL)) { 307 while (!(file->flags & FLAG_HLINK_EOL)) { 308 ndx = file->F_NEXT; 309 file = FPTR(ndx); (gdb) 310 } 311 } 312 do { 313 ndx = file->F_NEXT; 314 file = FPTR(ndx); 315 if (file->F_HLINDEX != SKIPPED_LINK) 316 continue; 317 hlink2 = f_name(file, NULL); 318 statret = link_stat(hlink2, &sx.st, 0); 319 maybe_hard_link(file, ndx, hlink2, statret, &sx, (gdb) 320 hlink1, &st, itemizing, code); 321 #ifdef SUPPORT_ACLS 322 if (preserve_acls) 323 free_acl(&sx); 324 #endif 325 if (remove_source_files == 1 && do_xfers) { 326 char numbuf[4]; 327 SIVAL(numbuf, 0, ndx); 328 send_msg(MSG_SUCCESS, numbuf, 4); 329 } (gdb) list maybe_hard_link 149 #ifdef SUPPORT_HARD_LINKS 150 static int maybe_hard_link(struct file_struct *file, int ndx, 151 char *fname, int statret, statx *sxp, 152 char *toname, STRUCT_STAT *to_st, 153 int itemizing, enum logcode code) 154 { 155 if (statret == 0) { 156 if (sxp->st.st_dev == to_st->st_dev 157 && sxp->st.st_ino == to_st->st_ino) { 158 if (itemizing) { (gdb) 159 #ifdef SUPPORT_ACLS 160 if (preserve_acls && !ACL_READY(*sxp)) 161 get_acl(fname, sxp); 162 #endif 163 itemize(file, ndx, statret, sxp, 164 ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 165 0, ""); 166 } 167 return 0; 168 } (gdb) quit
acl-statx-init.patch
Description: Binary data