[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

system/2208: Incorrect 'join' behaviour?




>Number:         2208
>Category:       system
>Synopsis:       Inconsistent field ordering between pairable and unpairable lines
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Nov 27 17:20:02 MST 2001
>Last-Modified:
>Originator:     Jonathan Martin
>Organization:
Department of Computing Science at University of Alberta.
>Release:        OPENBSD_2_9
>Environment:
	System      : OpenBSD 2.9
	Architecture: OpenBSD.i386
	Machine     : i386
>Description:
When joining with the -a<num> flag, lines which are joined are output with
the join field first, with the rest of the fields following in the order they
appeared in the input.  However, lines which are not joined are output without
any reordering.  The man page is vague about how unpairable lines will appear
on output.  IRIX, Solaris, and GNU join all reorder unpairable lines so that
the join field is first.

>How-To-Repeat:
Input file foo:
a 1

Input file bar:
b 1
x 2 apple
y 2 orange

Command line: join -12 -22 -a2 foo bar

OpenBSD output:
1 a b
x 2 apple
y 2 orange

Other systems output:
1 a b
2 x apple
2 y orange


Side effects of a fix:
Unfortunately changing the behavior of join affects the /etc/security script
(the setuid and device change checks).  If join reorders the unpairable
fields, then additions and deletions placed in TMP2 will not match with
anything in CUR and TMP1 (which will still be the order that find output).
So every addition and deletion will also be flagged as a change, and will be
output twice.

>Fix:
The fix for join is simple.

Index: usr.bin/join/join.c
===================================================================
RCS file: /cvs/src/usr.bin/join/join.c,v
retrieving revision 1.13
diff -u -r1.13 join.c
--- usr.bin/join/join.c	2001/01/29 01:57:59	1.13
+++ usr.bin/join/join.c	2001/11/27 23:33:52
@@ -454,9 +454,15 @@
 			else
 				outfield(lp, 0, 1);
 		}
-	else
+	else	{
+		/*
+		 * Output the join field, then the remaining fields from F
+		 */
+		outfield(lp, F->joinf, 0);
 		for (cnt = 0; cnt < lp->fieldcnt; ++cnt)
-			outfield(lp, cnt, 0);
+			if (F->joinf != cnt)
+				outfield(lp, cnt, 0);
+	}
 	putchar('\n');
 	if (ferror(stdout))
 		err(1, "stdout");



The side-effect fix for /etc/security is less pleasant.  Basically it means
always re-ordering the output of the find so it is consistent with what join
will output later.

Index: etc/security
===================================================================
RCS file: /cvs/src/etc/security,v
retrieving revision 1.48
diff -u -r1.48 security
--- etc/security	2001/04/06 17:13:37	1.48
+++ etc/security	2001/11/27 23:32:58
@@ -473,7 +473,7 @@
 fi
 
 # Display any changes in the setuid/setgid file list.
-egrep -v '^[bc]' $LIST > $TMP1
+egrep -v '^[bc]' $LIST | join -110 -210 -v2 /dev/null - | sort +0 > $TMP1
 if [ -s $TMP1 ] ; then
 	# Check to make sure uudecode isn't setuid.
 	if grep -w uudecode $TMP1 > /dev/null ; then
@@ -489,7 +489,7 @@
 			:
 		else
 			> $TMP2
-			join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
+			join -11 -21 -v2 $CUR $TMP1 > $OUTPUT
 			if [ -s $OUTPUT ] ; then
 				echo "${pending}Setuid additions:"
 				pending=
@@ -497,7 +497,7 @@
 				echo ""
 			fi
 
-			join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
+			join -11 -21 -v1 $CUR $TMP1 > $OUTPUT
 			if [ -s $OUTPUT ] ; then
 				echo "${pending}Setuid deletions:"
 				pending=
@@ -505,8 +505,7 @@
 				echo ""
 			fi
 
-			sort +9 $TMP2 $CUR $TMP1 | \
-			    sed -e 's/[	 ][	 ]*/ /g' | uniq -u > $OUTPUT
+			sort +0 $TMP2 $CUR $TMP1 | uniq -u > $OUTPUT
 			if [ -s $OUTPUT ] ; then
 				echo "${pending}Setuid changes:"
 				pending=
@@ -545,7 +544,7 @@
 fi
 
 # Display any changes in the device file list.
-egrep '^[bc]' $LIST | sort +10 > $TMP1
+egrep '^[bc]' $LIST | join -111 -211 -v2 /dev/null - | sort +0 > $TMP1
 if [ -s $TMP1 ] ; then
 	CUR=/var/backups/device.current
 	BACK=/var/backups/device.backup
@@ -555,14 +554,14 @@
 			:
 		else
 			> $TMP2
-			join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
+			join -11 -21 -v2 $CUR $TMP1 > $OUTPUT
 			if [ -s $OUTPUT ] ; then
 				echo "Device additions:"
 				tee -a $TMP2 < $OUTPUT
 				echo ""
 			fi
 
-			join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
+			join -11 -21 -v1 $CUR $TMP1 > $OUTPUT
 			if [ -s $OUTPUT ] ; then
 				echo "Device deletions:"
 				tee -a $TMP2 < $OUTPUT
@@ -571,10 +570,8 @@
 
 			# Report any block device change.  Ignore character
 			# devices, only the name is significant.
-			cat $TMP2 $CUR $TMP1 | \
-			sed -e '/^c/d' | \
-			sort +10 | \
-			sed -e 's/[	 ][	 ]*/ /g' | \
+			sort +0 $TMP2 $CUR $TMP1 | \
+			awk '$2 !~ /c........./' | \
 			uniq -u > $OUTPUT
 			if [ -s $OUTPUT ] ; then
 				echo "Block device changes:"

>Audit-Trail:
>Unformatted: