Subject: struct file reference counts
To: None <tech-kern@netbsd.org>
From: None <jaromir.dolecek@artisys.cz>
List: tech-kern
Date: 12/14/2001 10:34:54
--ELM715089176-380-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII
Hi,
I'd like to bump the f_count and f_msgcount members of struct file
to 'u_long', so that they can't be overflowed easily (it's possible
now, since they are just 'short' and overflow is not checked anywhere).
I wonder if any DIAGNOSTIC/DEBUG checks need to be added too
for f_count/f_msgcount. I believe it's not necessary, see below.
Since 'maxfiles' is an 'int', number of descriptors (and thus
references to appropriate struct file) could not be bigger than 2
** (sizeof(int) * 8 - 1). Theoretically, the amount of all of
references might be temporarily higher than maxfiles if descriptor
passing is used. In that case, number of references might be as
high as (maxfiles + unp_rights), where both 'maxfiles' and 'unp_rights'
are 'int'.
On 32bit archs, the overflow can't actually happen - 2 * 2 **
(sizeof(int) * 8 - 1) references means there exist that number of
pointers to the struct, which would consume 4GB of physical &
virtual kernel memory, which is unfeasible even with Intel's PSE36
extension support. On LP64 archs, it is theoretically possible
for kernel to have 4GB memory just for the the file descriptor
pointers. However, (2 * 2 ** (sizeof(int) * 8 - 1)) still fits
into 'long' on LP64, so we are covered. Of course, unp_internalize()
should be changed to check for 'unp_rights' overflow and return
error if that would happen.
I'm appending the patch to fix this issue.
Opinions?
Jarda
--
Jaromir Dolecek <jaromir.dolecek@artisys.cz>
ARTISYS, s.r.o., Stursova 71, 61600 Brno, Czech Republic
phone: +420-5-41224836 / fax: +420-5-41224870 / http://www.artisys.cz
--ELM715089176-380-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII
Content-Disposition: attachment; filename=frefs.diff
Index: conf/param.c
===================================================================
RCS file: /cvsroot/syssrc/sys/conf/param.c,v
retrieving revision 1.39
diff -u -p -r1.39 param.c
--- param.c 2001/11/08 05:59:31 1.39
+++ param.c 2001/12/14 09:29:23
@@ -107,10 +107,12 @@ int tickadj = 240000 / (60 * HZ); /* ca
int rtc_offset = RTC_OFFSET;
int maxproc = NPROC;
int desiredvnodes = NVNODE;
-int maxfiles = MAXFILES;
int ncallout = 16 + NPROC; /* size of callwheel (rounded to ^2) */
u_long sb_max = SB_MAX; /* maximum socket buffer size */
int fscale = FSCALE; /* kernel uses `FSCALE', user uses `fscale' */
+
+/* (maxfiles + unp_rights) MUST fit into struct file's f_count/f_msgcount */
+int maxfiles = MAXFILES;
/*
* Various mbuf-related parameters. These can also be changed at run-time
Index: kern/uipc_usrreq.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/uipc_usrreq.c,v
retrieving revision 1.53
diff -u -p -r1.53 uipc_usrreq.c
--- uipc_usrreq.c 2001/11/12 15:25:34 1.53
+++ uipc_usrreq.c 2001/12/14 09:29:53
@@ -481,7 +481,9 @@ u_long unpst_recvspace = PIPSIZ;
u_long unpdg_sendspace = 2*1024; /* really max datagram size */
u_long unpdg_recvspace = 4*1024;
+/* (maxfiles + unp_rights) MUST fit into struct file's f_count/f_msgcount */
int unp_rights; /* file descriptors in flight */
+#define UNPRIGHTS_SZ INT_MAX
int
unp_attach(so)
@@ -939,6 +941,10 @@ unp_internalize(control, p)
return (EBADF);
}
+ /* Verify that unp_rights would not overflow */
+ if (__predict_false(unp_rights > INT_MAX - nfds))
+ return (EMFILE);
+
/* Make sure we have room for the struct file pointers */
morespace:
neededspace = CMSG_SPACE(nfds * sizeof(struct file *)) -
@@ -957,6 +963,14 @@ unp_internalize(control, p)
/* copy the data to the cluster */
memcpy(mtod(control, char *), cm, cm->cmsg_len);
cm = mtod(control, struct cmsghdr *);
+
+ /*
+ * Verify that unp_rights would not overflow again, we might
+ * have been blocked.
+ */
+ if (__predict_false(unp_rights > INT_MAX - nfds))
+ return (EMFILE);
+
goto morespace;
}
Index: sys/file.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/file.h,v
retrieving revision 1.30
diff -u -p -r1.30 file.h
--- file.h 2001/12/07 07:09:30 1.30
+++ file.h 2001/12/14 09:29:53
@@ -59,10 +59,9 @@ struct file {
#define DTYPE_VNODE 1 /* file */
#define DTYPE_SOCKET 2 /* communications endpoint */
#define DTYPE_PIPE 3 /* pipe */
- short f_type; /* descriptor type */
- short f_count; /* reference count */
- short f_msgcount; /* references from message queue */
- short f_pad0; /* spare */
+ int f_type; /* descriptor type */
+ long f_count; /* reference count */
+ long f_msgcount; /* references from message queue */
struct ucred *f_cred; /* creds associated with descriptor */
struct fileops {
int (*fo_read) (struct file *fp, off_t *offset,
--ELM715089176-380-0_--