ash: dont allow e.g. exec <&10 to attach to stript's fd!

function                                             old     new   delta
is_hidden_fd                                           -      61     +61
redirect                                            1135    1164     +29
popstring                                            134     140      +6
printf_main                                          635     637      +2
evalvar                                             1374    1376      +2
echo_main                                            294     296      +2
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 5/0 up/down: 102/0)             Total: 102 bytes

diff --git a/shell/ash.c b/shell/ash.c
index bd2433c..1117468 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4889,7 +4889,7 @@
 {
 	int i;
 
-	if (!rp) /* remebering was not requested */
+	if (!rp) /* remembering was not requested */
 		return 0;
 
 	for (i = 0; i < rp->pair_count; i++) {
@@ -4901,6 +4901,28 @@
 	return 1;
 }
 
+/* "hidden" fd is a fd used to read scripts, or a copy of such */
+static int is_hidden_fd(struct redirtab *rp, int fd)
+{
+	int i;
+	struct parsefile *pf = g_parsefile;
+	while (pf) {
+		if (fd == pf->fd) {
+			return 1;
+		}
+		pf = pf->prev;
+	}
+	if (!rp)
+		return 0;
+	fd |= COPYFD_RESTORE;
+	for (i = 0; i < rp->pair_count; i++) {
+		if (rp->two_fd[i].copy == fd) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
  * old file descriptors are stashed away so that the redirection can be
@@ -4950,8 +4972,15 @@
 	do {
 		fd = redir->nfile.fd;
 		if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
-			if (redir->ndup.dupfd == fd)
-				continue; /* redirect from/to same file descriptor */
+			int right_fd = redir->ndup.dupfd;
+			/* redirect from/to same file descriptor? */
+			if (right_fd == fd)
+				continue;
+			/* echo >&10 and 10 is a fd opened to the sh script? */
+			if (is_hidden_fd(sv, right_fd)) {
+				errno = EBADF; /* as if it is closed */
+				ash_msg_and_raise_error("%d: %m", right_fd);
+			}
 			newfd = -1;
 		} else {
 			newfd = openredirect(redir); /* always >= 0 */
@@ -4988,14 +5017,8 @@
 				/* "exec fd>&-" should not close fds
 				 * which point to script file(s).
 				 * Force them to be restored afterwards */
-				struct parsefile *pf = g_parsefile;
-				while (pf) {
-					if (fd == pf->fd) {
-						i |= COPYFD_RESTORE;
-						break;
-					}
-					pf = pf->prev;
-				}
+				if (is_hidden_fd(sv, fd))
+					i |= COPYFD_RESTORE;
 			}
 			if (fd == 2)
 				copied_fd2 = i;
@@ -9026,7 +9049,7 @@
 preadfd(void)
 {
 	int nr;
-	char *buf =  g_parsefile->buf;
+	char *buf = g_parsefile->buf;
 	parsenextc = buf;
 
 #if ENABLE_FEATURE_EDITING