tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Overflow in ptyfs
Hi,
four bytes may overflow in ptyfs_vfsops.c::ptyfs_mount().
mount(XX, XX, XX, data, data_len)
The kernel will copyin data_len bytes of data into a kernel-allocated buffer.
This kernel buffer and data_len will be given to the appropriate xx_mount()
function, where xx is a fs.
ptyfs_mount() does not handle it correctly:
264 if (*data_len != sizeof *args && *data_len != OSIZE)
265 return EINVAL;
Two sizes are accepted, sizeof(struct ptyfs_args) where ptyfs_args is
struct ptyfs_args {
int version;
gid_t gid;
mode_t mode;
int flags;
};
and OSIZE, the size of the old ptyfs_args structure, which does not have the
last 'flags' field.
278 if (args->version >= PTYFS_ARGSVERSION) {
279 args->flags = pmnt->pmnt_flags;
280 *data_len = sizeof *args;
281 } else {
282 *data_len = OSIZE;
283 }
Here, 'args->flags' is overwritten, depending on the argument version.
But 'data_len' and 'args->version' are user-controlled. Therefore, you can set
'args->version' to PTYFS_ARGSVERSION, and give 'data_len' = OSIZE. On that case,
the kernel will allocate and populate OSIZE bytes, and 'args->flags' will be
overwritten while it actually resides outside the allocated buffer. 4 bytes
overflow.
On NetBSD-current, KMEM_REDZONE will detect it, and will panic. On normal
systems, it won't cause any trouble: once rounded up to a kmem page,
sizeof(struct ptyfs_args) and OSIZE are equal, so the actual allocated size
does not change in both cases. It's not a "real" overflow.
--------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <fs/ptyfs/ptyfs.h>
#define OSIZE sizeof(struct { int f; gid_t g; mode_t m; })
int main() {
struct ptyfs_args args;
int ret;
args.version = PTYFS_ARGSVERSION;
ret = mount("ptyfs", "/dev/pts", MNT_GETARGS, &args, OSIZE);
/* NOTREACHED NetBSD-current (KMEM_REDZONE) */
printf("RET: %d\n", ret);
}
--------------------------------------------------------------------------------
Index: ptyfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/ptyfs/ptyfs_vfsops.c,v
retrieving revision 1.50
diff -u -r1.50 ptyfs_vfsops.c
--- ptyfs_vfsops.c 16 Apr 2014 18:55:18 -0000 1.50
+++ ptyfs_vfsops.c 11 Aug 2014 06:58:35 -0000
@@ -261,8 +261,10 @@
if (args == NULL)
return EINVAL;
- if (*data_len != sizeof *args && *data_len != OSIZE)
- return EINVAL;
+ if (*data_len != sizeof *args) {
+ if (*data_len != OSIZE || args->version >= PTYFS_ARGSVERSION)
+ return EINVAL;
+ }
if (UIO_MX & (UIO_MX - 1)) {
log(LOG_ERR, "ptyfs: invalid directory entry size");
Ok/Comments?
Home |
Main Index |
Thread Index |
Old Index