summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Src/Modules/socket.c41
-rw-r--r--Src/Modules/tcp.c25
-rw-r--r--Src/Modules/zftp.c7
-rw-r--r--Src/exec.c14
-rw-r--r--Src/params.c8
-rw-r--r--Src/utils.c8
-rw-r--r--Src/zsh.h1
8 files changed, 72 insertions, 39 deletions
diff --git a/ChangeLog b/ChangeLog
index ce85369b7..2287db1bd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2026-07-25 Mikael Magnusson <mikachu@gmail.com>
+
+ * 54986: Src/Modules/socket.c, Src/Modules/tcp.c,
+ Src/Modules/zftp.c, Src/exec.c, Src/params.c, Src/utils.c,
+ Src/zsh.h: actually prevent FDT_MODULE fds from being closed
+ by user
+
2026-07-21 Mikael Magnusson <mikachu@gmail.com>
* 54985: Src/Zle/zle_main.c, Src/hist.c, Src/zsh.h: fix crash
diff --git a/Src/Modules/socket.c b/Src/Modules/socket.c
index 3ecab42c9..95235453e 100644
--- a/Src/Modules/socket.c
+++ b/Src/Modules/socket.c
@@ -119,17 +119,18 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
return 1;
}
- addmodulefd(sfd, FDT_EXTERNAL);
-
if (targetfd) {
sfd = redup(sfd, targetfd);
- }
- else {
- /* move the fd since no one will want to read from it */
+ if (sfd == -1) {
+ zerrnam(nam, "cannot duplicate socket fd to %d: %e", targetfd, errno);
+ return 1;
+ }
+ } else {
+ targetfd = sfd; /* for error message */
sfd = movefd(sfd);
}
if (sfd == -1) {
- zerrnam(nam, "cannot duplicate fd %d: %e", sfd, errno);
+ zerrnam(nam, "could not move socket fd %d: %e", targetfd, errno);
return 1;
}
@@ -209,20 +210,20 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
return 1;
}
- addmodulefd(rfd, FDT_EXTERNAL);
-
if (targetfd) {
sfd = redup(rfd, targetfd);
- if (sfd < 0) {
+ if (sfd == -1) {
zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno);
- zclose(rfd);
return 1;
}
- fdtable[sfd] = FDT_EXTERNAL;
+ } else {
+ sfd = movefd(rfd);
}
- else {
- sfd = rfd;
+ if (sfd == -1) {
+ zerrnam(nam, "could not move socket fd %d: %e", rfd, errno);
+ return 1;
}
+ fdtable[sfd] = FDT_EXTERNAL;
setiparam_no_convert("REPLY", (zlong)sfd);
@@ -268,17 +269,21 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
}
else
{
- addmodulefd(sfd, FDT_EXTERNAL);
-
if (targetfd) {
- if (redup(sfd, targetfd) < 0) {
+ if (redup(sfd, targetfd) == -1) {
zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno);
- zclose(sfd);
return 1;
}
sfd = targetfd;
- fdtable[sfd] = FDT_EXTERNAL;
+ } else {
+ targetfd = sfd; /* for error message */
+ sfd = movefd(sfd);
}
+ if (sfd == -1) {
+ zerrnam(nam, "could not move socket fd %d: %e", targetfd, errno);
+ return 1;
+ }
+ fdtable[sfd] = FDT_EXTERNAL;
setiparam_no_convert("REPLY", (zlong)sfd);
diff --git a/Src/Modules/tcp.c b/Src/Modules/tcp.c
index 4366f3c02..36c3dca37 100644
--- a/Src/Modules/tcp.c
+++ b/Src/Modules/tcp.c
@@ -489,18 +489,26 @@ bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
if (targetfd) {
sess->fd = redup(sess->fd, targetfd);
+ if (sess->fd < 0) {
+ zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno);
+ tcp_close(sess);
+ return 1;
+ }
}
else {
- /* move the fd since no one will want to read from it */
+ targetfd = sess->fd; /* just stashing here for error message */
sess->fd = movefd(sess->fd);
}
if (sess->fd == -1) {
- zwarnnam(nam, "cannot duplicate fd %d: %e", sess->fd, errno);
+ zwarnnam(nam, "cannot duplicate fd %d: %e", targetfd, errno);
tcp_close(sess);
return 1;
}
+ /* disallow to be closed explicitly, after movefd set it to INTERNAL */
+ fdtable[sess->fd] = FDT_MODULE;
+
setiparam_no_convert("REPLY", (zlong)sess->fd);
if (verbose)
@@ -588,19 +596,24 @@ bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
return 1;
}
- /* redup expects fd is already registered */
- addmodulefd(rfd, FDT_MODULE);
-
if (targetfd) {
sess->fd = redup(rfd, targetfd);
if (sess->fd < 0) {
zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno);
+ tcp_close(sess);
return 1;
}
}
else {
- sess->fd = rfd;
+ sess->fd = movefd(rfd);
+ }
+ if (sess->fd < 0) {
+ zerrnam(nam, "could not move socket fd %d: %e", rfd, errno);
+ tcp_close(sess);
+ return 1;
}
+ /* disallow to be closed explicitly */
+ fdtable[sess->fd] = FDT_MODULE;
setiparam_no_convert("REPLY", (zlong)sess->fd);
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 738b22b43..b631c57cf 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -458,7 +458,7 @@ zfunpipe(void)
}
/*
- * Same as movefd(), but don't mark the fd in the zsh tables,
+ * Same as movefd(), but mark the fd as FDT_MODULE in the zsh tables,
* because we only want it closed by zftp. However, we still
* need to shift the fd's out of the way of the user-visible 0-9.
*/
@@ -473,9 +473,10 @@ zfmovefd(int fd)
#else
int fe = zfmovefd(dup(fd));
#endif
- close(fd);
+ zclose(fd);
fd = fe;
}
+ addmodulefd(fd, FDT_MODULE);
return fd;
}
@@ -1040,7 +1041,7 @@ zfclosedata(void)
{
if (zfsess->dfd == -1)
return;
- close(zfsess->dfd);
+ zclose(zfsess->dfd);
zfsess->dfd = -1;
}
diff --git a/Src/exec.c b/Src/exec.c
index 20caf40d1..5f849db63 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -3885,10 +3885,12 @@ execcmd_exec(Estate state, Execcmd_params eparams,
bad = 1;
}
if (!bad && fn->fd1 <= max_zsh_fd) {
- if (fn->fd1 >= 10 &&
- (fdtable[fn->fd1] & FDT_TYPE_MASK) ==
- FDT_INTERNAL)
- bad = 3;
+ int fdt = fdtable[fn->fd1] & FDT_TYPE_MASK;
+ if ((fn->fd1 >= 10 && fdt == FDT_INTERNAL) ||
+ fdt == FDT_MODULE)
+ {
+ bad = 3 + (fdt == FDT_MODULE);
+ }
}
}
}
@@ -3896,7 +3898,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
const char *bad_msg[] = {
"parameter %s does not contain a file descriptor",
"can't close file descriptor from readonly parameter %s",
- "file descriptor %d used by shell, not closed"
+ "file descriptor %d used by shell, not closed",
+ "file descriptor %d used by module, not closed",
};
if (bad > 2)
zwarn(bad_msg[bad-1], fn->fd1);
@@ -3947,6 +3950,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
*/
(fn->fd2 <= max_zsh_fd &&
((fdtable[fn->fd2] != FDT_UNUSED &&
+ fdtable[fn->fd2] != FDT_MODULE &&
fdtable[fn->fd2] != FDT_EXTERNAL) ||
fn->fd2 == coprocin ||
fn->fd2 == coprocout))) {
diff --git a/Src/params.c b/Src/params.c
index 7409ff530..716dd66c3 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2944,7 +2944,7 @@ setarrvalue(Value v, char **val)
v->end = oldlen;
/* Strings before slice + strings from val + strings after slice */
- newlen = v->start + vallen + MAX(0, oldlen - v->end);
+ newlen = v->start + vallen + maximum(0, oldlen - v->end);
if (v->pm->gsu.a->setfn == arrsetfn && old == v->pm->u.arr) {
v->pm->u.arr = NULL; /* Steal the old array */
@@ -2964,7 +2964,7 @@ setarrvalue(Value v, char **val)
sizeof(char *) * (oldlen - v->end));
} else {
new = (char **) zalloc(sizeof(char *) * (newlen + 1));
- for (p = new, q = old, i = MIN(v->start, oldlen); i > 0; i--)
+ for (p = new, q = old, i = minimum(v->start, oldlen); i > 0; i--)
*p++ = ztrdup(*q++);
if (v->end < oldlen)
for (p = new + v->start + vallen, q = old + v->end; *q;)
@@ -6351,7 +6351,7 @@ resolve_nameref_rec(Param pm, const Param stop, int keep_lastref)
int ppar = zstrtol(refname, NULL, 10);
if (ppar >= argnparams_size) {
size_t old_size = argnparams_size;
- size_t new_size = argnparams_size = MAX(2 * old_size, ppar);
+ size_t new_size = argnparams_size = maximum(2 * old_size, ppar);
argnparams = zrealloc(argnparams, new_size * sizeof(Param));
memset(argnparams + old_size, 0,
(new_size - old_size) * sizeof(Param));
@@ -6443,7 +6443,7 @@ setscope_base(Param pm, int base)
LinkList refs;
if (base >= scoperefs_num) {
int old_num = scoperefs_num;
- int new_num = scoperefs_num = MAX(2 * base, 8);
+ int new_num = scoperefs_num = maximum(2 * base, 8);
scoperefs = zrealloc(scoperefs, new_num * sizeof(refs));
memset(scoperefs + old_num, 0, (new_num - old_num) * sizeof(refs));
}
diff --git a/Src/utils.c b/Src/utils.c
index 1130415db..372d2a828 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -2050,7 +2050,7 @@ redup(int x, int y)
if (dup2(x, y) == -1) {
ret = -1;
} else {
- check_fd_table(y);
+ check_fd_table(maximum(x, y));
fdtable[y] = fdtable[x];
if (fdtable[y] == FDT_FLOCK || fdtable[y] == FDT_FLOCK_EXEC)
fdtable[y] = FDT_INTERNAL;
@@ -2059,16 +2059,18 @@ redup(int x, int y)
* Closing any fd to the locked file releases the lock.
* This isn't expected to happen, it's here for completeness.
*/
+ check_fd_table(x);
if (fdtable[x] == FDT_FLOCK)
fdtable_flocks--;
zclose(x);
- }
+ } else
+ check_fd_table(x);
return ret;
}
/*
- * Add an fd opened ithin a module.
+ * Add an fd opened within a module.
*
* fdt is the type of the fd; see the FDT_ definitions in zsh.h.
* The most likely failures are:
diff --git a/Src/zsh.h b/Src/zsh.h
index 2054c07b6..5a989ff47 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -29,6 +29,7 @@
/* A few typical macros */
#define minimum(a,b) ((a) < (b) ? (a) : (b))
+#define maximum(a,b) ((a) > (b) ? (a) : (b))
/*
* Our longest integer type: will be a 64 bit either if long already is,