Subject: Bug#547902: dash only reads the first character from pipe (bash reads whole line)

From: Corin <[email-masked]>
Date: Tue, 22 Sep 2009 15:49:40 +0200

Package: dash
Version: 0.5.5.1-2.3
Severity: important

The 'read' command seems to only read the first character and not the whole line.

Example / comparison with bash:

# /bin/dash
# read MAX </proc/sys/net/netfilter/nf_conntrack_max
# echo $MAX
2

# /bin/bash
# read MAX </proc/sys/net/netfilter/nf_conntrack_max
# echo $MAX
262144

-- System Information:
Debian Release: squeeze/sid
  APT prefers testing
  APT policy: (990, 'testing'), (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.26-2-vserver-amd64 (SMP w/4 CPU cores)
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages dash depends on:
ii  debianutils                  3.2.1       Miscellaneous utilities specific t
ii  dpkg                         1.15.3.1+b1 Debian package management system
ii  libc6                        2.9-25      GNU C Library: Shared libraries

dash recommends no packages.

dash suggests no packages.

-- debconf information:
* dash/sh: true

---

From: Gerrit Pape <[email-masked]>
Date: Tue, 29 Sep 2009 11:59:55 +0000

> # read MAX </proc/sys/net/netfilter/nf_conntrack_max

Hi, this doesn't look like a bug in dash, but in the kernel's
implementation of the /proc/sys/net/ hierarchy.  If you copy the file to
/tmp/, it works just fine.

cat <<EOT >t.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char **argv) {
	char c;
	int fd = open(argv[1], O_RDONLY);
	if (fd == -1) return 1;
	for (;;) {
		int i = read(fd, &c, 1);
		if (i == 0) break;
		if (i == -1) return 2;
		if (write(1, &c, 1) == -1) return 3;
	}
	write(1, "\n", 1);
	return 0;
}
EOT
gcc t.c
./a.out /proc/sys/net/unix/max_dgram_qlen
cat /proc/sys/net/unix/max_dgram_qlen
cp /proc/sys/net/unix/max_dgram_qlen /tmp/
./a.out /tmp/max_dgram_qlen

Regards, Gerrit.

---

From: Netskin | Corin Langosch <[email-masked]>
Date: Thu, 08 Oct 2009 13:34:40 +0200

Hi,

I'm still not sure if it's a kernel bug/misbehavior, as bash works fine 
on the same system. And even if it's a kernel bug, shouldn't dash 
contain the same work-around as bash seems to have?

Fact is, when upgrading debian (and so dash becomes the default shell) 
some applications break because of this. One example are munin plugins, 
which is where I discovered the bug/ regression. Changing the shebang 
line in the munin plugins from /bin/sh (symlink to /bin/dash) to 
/bin/bash solves the problems.

Corin

---

From: Gerrit Pape <[email-masked]>
Date: Tue, 13 Oct 2009 10:42:21 +0000

reassign 547902 linux-2.6

---

From: Gerrit Pape <[email-masked]>
Date: Tue, 13 Oct 2009 11:13:01 +0000

tags 547902 + patch
quit

Hi, please see http://bugs.debian.org/547902

Here's a patch from Christian Hohnstaedt <[email-masked]>

Thanks, Gerrit.

---
Testparameter:
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; do dd if=/proc/sys/net/ipv4/tcp_wmem bs=$i 2>/dev/null; done

for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; do dd if=/proc/sys/net/ipv4/tcp_wmem skip=$i bs=1 2>/dev/null |wc -c ; done

diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 9270125..038df14 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2117,17 +2117,16 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
 #define TMPBUFLEN 21
 	int *i, vleft, first=1, neg, val;
 	unsigned long lval;
-	size_t left, len;
+	size_t left, len, off;
 	
 	char buf[TMPBUFLEN], *p;
 	char __user *s = buffer;
 	
-	if (!tbl_data || !table->maxlen || !*lenp ||
-	    (*ppos && !write)) {
+	if (!tbl_data || !table->maxlen || !*lenp) {
 		*lenp = 0;
 		return 0;
 	}
-	
+	off = 0;
 	i = (int *) tbl_data;
 	vleft = table->maxlen / sizeof(*i);
 	left = *lenp;
@@ -2176,25 +2175,31 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
 			if (conv(&neg, &lval, i, 1, data))
 				break;
 		} else {
+			loff_t diff;
 			p = buf;
-			if (!first)
-				*p++ = '\t';
-	
 			if (conv(&neg, &lval, i, 0, data))
 				break;
 
-			sprintf(p, "%s%lu", neg ? "-" : "", lval);
-			len = strlen(buf);
-			if (len > left)
-				len = left;
-			if(copy_to_user(s, buf, len))
-				return -EFAULT;
-			left -= len;
-			s += len;
+			len = sprintf(p, "%s%s%lu", first ? "" : "\t",
+						neg ? "-" : "", lval);
+			diff = *ppos - off;
+			off += len;
+			if (diff > 0 && diff < len) {
+				p += diff;
+				len -= diff;
+			}
+			if (off > *ppos) {
+				if (len > left)
+					len = left;
+				if(copy_to_user(s, p, len))
+					return -EFAULT;
+				left -= len;
+				s += len;
+			}
 		}
 	}
 
-	if (!write && !first && left) {
+	if (!write && !first && left && off >= *ppos) {
 		if(put_user('\n', s))
 			return -EFAULT;
 		left--, s++;

---

From: Ben Hutchings <[email-masked]>
Date: Sat, 17 Oct 2009 01:36:03 +0100

> Here's a patch from Christian Hohnstaedt <[email-masked]>
[...]

Let us know when this change is accepted upstream.

Ben.

-- 
Ben Hutchings
It is impossible to make anything foolproof because fools are so ingenious.

---

From: Gerrit Pape <[email-masked]>
Date: Fri, 13 Nov 2009 11:00:26 +0000

> Let us know when this change is accepted upstream.

Sorry, I neither forwarded it upstream, nor follow upstream development.

Regards, Gerrit.

---

From: Ben Hutchings <[email-masked]>
Date: Fri, 13 Nov 2009 12:34:10 +0000

> Sorry, I neither forwarded it upstream, nor follow upstream development.

Then we will not apply your patch.

Ben.

-- 
Ben Hutchings
The two most common things in the universe are hydrogen and stupidity.

---

From: Moritz Muehlenhoff <[email-masked]>
Date: Wed, 18 Nov 2009 22:13:48 +0100

> quit

[ Adding Christian to CC: ]

Christian, did you submit your patch upstream?

Cheers,
        Moritz

---

From: Christian Hohnstaedt <[email-masked]>
Date: Thu, 19 Nov 2009 09:27:47 +0100

> Christian, did you submit your patch upstream?

No, not yet.

It still has the problem that reading the value(s) bytewise returns garbage
if the value(s) change during reading.

But I can try to send it to lkml and see what they say.
Shall I point to this bug-report and may I add a "Tested-by" line ?

	Christian

> > +	if (!write && !first && left && off >= *ppos) {
Christian Hohnstaedt

-- 
Christian Hohnstaedt / Project Manager Hardware and Manufacturing

Innominate Security Technologies AG / protecting industrial networks
tel: +49.30.921028.208 / fax: +49.30.921028.020
Rudower Chaussee 13, D-12489 Berlin / http://www.innominate.com

Register Court: AG Charlottenburg, HR B 81603
Management Board: Dirk Seewald
Chairman of the Supervisory Board: Volker Bibelhausen

---

From: Moritz Muehlenhoff <[email-masked]>
Date: Tue, 24 Nov 2009 22:16:06 +0100

> > Christian, did you submit your patch upstream?

Please keep this bug CCed if you submit it.
 
> Shall I point to this bug-report and may I add a "Tested-by" line ?

I didn't test it myself, but maybe Corin can give feedback on this.

Cheers,
        Moritz

---

From: [email-masked] (Debian Bug Tracking System)
Date: Fri, 06 May 2011 19:18:09 +0000

This is an automatic notification regarding your Bug report
which was filed against the linux-2.6 package:

#547902: dash only reads the first character from pipe (bash reads whole line)

It has been closed by Moritz Muehlenhoff <[email-masked]>.

Their explanation is attached below along with your original report.
If this explanation is unsatisfactory and you have not received a
better one in a separate message then please contact Moritz Muehlenhoff <[email-masked]> by
replying to this email.

-- 
547902: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=547902
Debian Bug Tracking System
Contact [email-masked] with problems

Subject: Re: Bug#547902: dash only reads the first character from pipe (bash reads whole line)
From: Moritz Muehlenhoff <[email-masked]>
To: Christian Hohnstaedt <[email-masked]>
Cc: [email-masked]
Date: Fri, 6 May 2011 21:15:45 +0200

> Please keep this bug CCed if you submit it.

Closing due to lack of activity.

Cheers,
        Moritz

Subject: dash only reads the first character from pipe (bash reads whole line)
From: Corin <[email-masked]>
To: Debian Bug Tracking System <[email-masked]>
Date: Tue, 22 Sep 2009 15:49:40 +0200

Package: dash
Version: 0.5.5.1-2.3
Severity: important

# /bin/dash

# /bin/bash

-- System Information:

-- debconf information:
* dash/sh: true

---

From: [email-masked] (Debian Bug Tracking System)
Date: Fri, 06 May 2011 19:18:10 +0000

Cheers,
        Moritz

Subject: dash only reads the first character from pipe (bash reads whole line)
From: Corin Langosch <[email-masked]>
To: Debian Bug Tracking System <[email-masked]>
Date: Tue, 22 Sep 2009 15:59:45 +0200

Package: dash
Version: 0.5.5.1-2.3
Severity: important

# /bin/dash

# /bin/bash

-- System Information:

-- debconf information:
* dash/sh: true

---

From: Jonathan Nieder <[email-masked]>
Date: Fri, 6 May 2011 14:26:07 -0500

reassign 547906 dash 0.5.6.1-1~exp2
reopen 547906
tags 547906 = patch
quit

> Closing due to lack of activity.

I'll take it.  Will reassign back to linux-2.6 if there is progress.

---

From: Herbert Xu <[email-masked]>
Date: Sun, 19 May 2024 18:08:47 +0800

This will be fixed upstream soon with

https://patchwork.kernel.org/project/dash/patch/[email-masked]/

Cheers,
-- 
Email: Herbert Xu <[email-masked]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt