summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2016-04-20 15:15:54 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2016-04-20 15:15:54 +0000
commit3ea40c8ad52fbaced2ec68a5675083be7f73f09e (patch)
tree9d2510cb659f78376ab9a76f4d66034bcaf71387
parent5fb19d2284646c4de42be831278121aadf9af84c (diff)
downloadillumos-joyent-3ea40c8ad52fbaced2ec68a5675083be7f73f09e.tar.gz
OS-5331 Add support for sysctl net.ipv4.ip_local_port_range to LX proc
OS-5342 writing to writable proc files can fail OS-5344 streamline proc write support Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_proc.h3
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prsubr.c28
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prvnops.c417
3 files changed, 272 insertions, 176 deletions
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_proc.h b/usr/src/uts/common/brand/lx/procfs/lx_proc.h
index 2ec23ba55d..131a061062 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_proc.h
+++ b/usr/src/uts/common/brand/lx/procfs/lx_proc.h
@@ -108,6 +108,7 @@ extern "C" {
* (directories and files contained therein).
*/
typedef enum lxpr_nodetype {
+ LXPR_INVALID, /* nodes start at 1 */
LXPR_PROCDIR, /* /proc */
LXPR_PIDDIR, /* /proc/<pid> */
LXPR_PID_AUXV, /* /proc/<pid>/auxv */
@@ -221,6 +222,7 @@ typedef enum lxpr_nodetype {
LXPR_SYS_NET_COREDIR, /* /proc/sys/net/core */
LXPR_SYS_NET_CORE_SOMAXCON, /* /proc/sys/net/core/somaxconn */
LXPR_SYS_NET_IPV4DIR, /* /proc/sys/net/ipv4 */
+ LXPR_SYS_NET_IPV4_IP_LPORT_RANGE, /* .../net/ipv4/ip_local_port_range */
LXPR_SYS_NET_IPV4_TCP_FIN_TO, /* /proc/sys/net/ipv4/tcp_fin_timeout */
LXPR_SYS_NET_IPV4_TCP_KA_INT, /* .../net/ipv4/tcp_keepalive_intvl */
LXPR_SYS_NET_IPV4_TCP_KA_TIM, /* .../net/ipv4/tcp_keepalive_time */
@@ -299,6 +301,7 @@ extern void lxpr_fininodecache();
extern void lxpr_initrootnode(lxpr_node_t **, vfs_t *);
extern ino_t lxpr_inode(lxpr_nodetype_t, pid_t, int);
extern ino_t lxpr_parentinode(lxpr_node_t *);
+extern boolean_t lxpr_is_writable(lxpr_nodetype_t);
extern lxpr_node_t *lxpr_getnode(vnode_t *, lxpr_nodetype_t, proc_t *, int);
extern void lxpr_freenode(lxpr_node_t *);
extern vnode_t *lxpr_lookup_fdnode(vnode_t *, const char *);
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prsubr.c b/usr/src/uts/common/brand/lx/procfs/lx_prsubr.c
index f900662ee6..469db04024 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prsubr.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prsubr.c
@@ -417,6 +417,15 @@ lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int desc)
/*
* Do node specific stuff
*/
+ if (lxpr_is_writable(type)) {
+ /* These two have different modes; handled later. */
+ if (type != LXPR_PID_FD_FD && type != LXPR_PID_TID_FD_FD) {
+ vp->v_type = VREG;
+ lxpnp->lxpr_mode = 0644;
+ return (lxpnp);
+ }
+ }
+
switch (type) {
case LXPR_PROCDIR:
vp->v_flag |= VROOT;
@@ -494,6 +503,7 @@ lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int desc)
break;
case LXPR_PID_FD_FD:
+ case LXPR_PID_TID_FD_FD:
ASSERT(p != NULL);
/* lxpr_realvp is set after we return */
lxpnp->lxpr_mode = 0700; /* read-write-exe owner only */
@@ -536,24 +546,6 @@ lxpr_getnode(vnode_t *dp, lxpr_nodetype_t type, proc_t *p, int desc)
lxpnp->lxpr_mode = 0400; /* read-only by owner only */
break;
- case LXPR_PID_LOGINUID:
- case LXPR_PID_OOM_SCR_ADJ:
- case LXPR_PID_TID_OOM_SCR_ADJ:
- case LXPR_SYS_KERNEL_COREPATT:
- case LXPR_SYS_KERNEL_SHMALL:
- case LXPR_SYS_KERNEL_SHMMAX:
- case LXPR_SYS_NET_CORE_SOMAXCON:
- case LXPR_SYS_NET_IPV4_TCP_FIN_TO:
- case LXPR_SYS_NET_IPV4_TCP_KA_INT:
- case LXPR_SYS_NET_IPV4_TCP_KA_TIM:
- case LXPR_SYS_NET_IPV4_TCP_SACK:
- case LXPR_SYS_NET_IPV4_TCP_WINSCALE:
- case LXPR_SYS_VM_OVERCOMMIT_MEM:
- case LXPR_SYS_VM_SWAPPINESS:
- vp->v_type = VREG;
- lxpnp->lxpr_mode = 0644;
- break;
-
default:
vp->v_type = VREG;
lxpnp->lxpr_mode = 0444; /* read-only by all */
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
index 8b33ed45da..1c7ceee11d 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
@@ -233,6 +233,8 @@ static void lxpr_read_sys_kernel_shmmax(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_kernel_shmmni(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_kernel_threads_max(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_net_core_somaxc(lxpr_node_t *, lxpr_uiobuf_t *);
+static void lxpr_read_sys_net_ipv4_ip_lport_range(lxpr_node_t *,
+ lxpr_uiobuf_t *);
static void lxpr_read_sys_net_ipv4_tcp_fin_to(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_net_ipv4_tcp_ka_int(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_net_ipv4_tcp_ka_tim(lxpr_node_t *, lxpr_uiobuf_t *);
@@ -248,6 +250,8 @@ static int lxpr_write_pid_loginuid(lxpr_node_t *, uio_t *, cred_t *,
caller_context_t *);
static int lxpr_write_sys_net_core_somaxc(lxpr_node_t *, uio_t *, cred_t *,
caller_context_t *);
+static int lxpr_write_sys_net_ipv4_ip_lport_range(lxpr_node_t *, uio_t *,
+ cred_t *, caller_context_t *);
static int lxpr_write_sys_net_ipv4_tcp_fin_to(lxpr_node_t *, uio_t *, cred_t *,
caller_context_t *);
static int lxpr_write_sys_net_ipv4_tcp_ka_int(lxpr_node_t *, uio_t *,
@@ -545,10 +549,11 @@ static lxpr_dirent_t sys_net_coredir[] = {
/*
* contents of /proc/sys/net/ipv4 directory
- * See the Linux tcp(7) man page for descriptions and the illumos tcp(7p)
- * man page for the native descriptions.
+ * See the Linux ip(7) & tcp(7) man pages for descriptions and the illumos
+ * ip(7p) & tcp(7p) man pages for the native descriptions.
*/
static lxpr_dirent_t sys_net_ipv4dir[] = {
+ { LXPR_SYS_NET_IPV4_IP_LPORT_RANGE, "ip_local_port_range" },
{ LXPR_SYS_NET_IPV4_TCP_FIN_TO, "tcp_fin_timeout" },
{ LXPR_SYS_NET_IPV4_TCP_KA_INT, "tcp_keepalive_intvl" },
{ LXPR_SYS_NET_IPV4_TCP_KA_TIM, "tcp_keepalive_time" },
@@ -573,6 +578,57 @@ static lxpr_dirent_t sys_vmdir[] = {
#define SYS_VMDIRFILES (sizeof (sys_vmdir) / sizeof (sys_vmdir[0]))
/*
+ * Table for standard writable files. Non-standard writable files not in this
+ * table can be handled explicitly as special cases.
+ * This table drives lxpr_is_writable, lxpr_write, and lxpr_create.
+ * Note that the entries LXPR_PID_FD_FD and LXPR_PID_TID_FD_FD exist in the
+ * table both to verify writability and to satisfy opening with O_CREATE.
+ */
+typedef struct wftab {
+ lxpr_nodetype_t wft_type; /* file entry type */
+ int (*wft_wrf)(lxpr_node_t *, struct uio *, cred_t *,
+ caller_context_t *); /* write function */
+} wftab_t;
+
+static wftab_t wr_tab[] = {
+ {LXPR_PID_FD_FD, NULL},
+ {LXPR_PID_LOGINUID, lxpr_write_pid_loginuid},
+ {LXPR_PID_OOM_SCR_ADJ, NULL},
+ {LXPR_PID_TID_FD_FD, NULL},
+ {LXPR_PID_TID_OOM_SCR_ADJ, NULL},
+ {LXPR_SYS_KERNEL_COREPATT, lxpr_write_sys_kernel_corepatt},
+ {LXPR_SYS_KERNEL_SHMALL, NULL},
+ {LXPR_SYS_KERNEL_SHMMAX, NULL},
+ {LXPR_SYS_NET_CORE_SOMAXCON, lxpr_write_sys_net_core_somaxc},
+ {LXPR_SYS_NET_IPV4_IP_LPORT_RANGE,
+ lxpr_write_sys_net_ipv4_ip_lport_range},
+ {LXPR_SYS_NET_IPV4_TCP_FIN_TO, lxpr_write_sys_net_ipv4_tcp_fin_to},
+ {LXPR_SYS_NET_IPV4_TCP_KA_INT, lxpr_write_sys_net_ipv4_tcp_ka_int},
+ {LXPR_SYS_NET_IPV4_TCP_KA_TIM, lxpr_write_sys_net_ipv4_tcp_ka_tim},
+ {LXPR_SYS_NET_IPV4_TCP_SACK, lxpr_write_sys_net_ipv4_tcp_sack},
+ {LXPR_SYS_NET_IPV4_TCP_WINSCALE, lxpr_write_sys_net_ipv4_tcp_winscale},
+ {LXPR_SYS_VM_OVERCOMMIT_MEM, NULL},
+ {LXPR_SYS_VM_SWAPPINESS, NULL},
+ {LXPR_INVALID, NULL}
+};
+
+/*
+ * Centralized test for the standard writable proc files. Other non-standard
+ * writable files might be handled separately.
+ */
+boolean_t
+lxpr_is_writable(lxpr_nodetype_t type)
+{
+ int i;
+
+ for (i = 0; wr_tab[i].wft_type != LXPR_INVALID; i++) {
+ if (wr_tab[i].wft_type == type)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
* lxpr_open(): Vnode operation for VOP_OPEN()
*/
static int
@@ -584,30 +640,9 @@ lxpr_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
vnode_t *rvp;
int error = 0;
- if (flag & FWRITE) {
- /* Restrict writes to certain files */
- switch (type) {
- case LXPR_PID_LOGINUID:
- case LXPR_PID_TID_LOGINUID:
- case LXPR_PID_OOM_SCR_ADJ:
- case LXPR_PID_TID_OOM_SCR_ADJ:
- case LXPR_SYS_KERNEL_COREPATT:
- case LXPR_SYS_KERNEL_SHMALL:
- case LXPR_SYS_KERNEL_SHMMAX:
- case LXPR_SYS_NET_CORE_SOMAXCON:
- case LXPR_SYS_NET_IPV4_TCP_FIN_TO:
- case LXPR_SYS_NET_IPV4_TCP_KA_INT:
- case LXPR_SYS_NET_IPV4_TCP_KA_TIM:
- case LXPR_SYS_NET_IPV4_TCP_SACK:
- case LXPR_SYS_NET_IPV4_TCP_WINSCALE:
- case LXPR_SYS_VM_OVERCOMMIT_MEM:
- case LXPR_SYS_VM_SWAPPINESS:
- case LXPR_PID_FD_FD:
- case LXPR_PID_TID_FD_FD:
- break;
- default:
- return (EPERM);
- }
+ /* Restrict writes to certain files */
+ if ((flag & FWRITE) && !lxpr_is_writable(type)) {
+ return (EPERM);
}
/*
@@ -673,6 +708,7 @@ lxpr_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
}
static void (*lxpr_read_function[LXPR_NFILES])() = {
+ NULL, /* invalid */
lxpr_read_isdir, /* /proc */
lxpr_read_isdir, /* /proc/<pid> */
lxpr_read_pid_auxv, /* /proc/<pid>/auxv */
@@ -786,6 +822,7 @@ static void (*lxpr_read_function[LXPR_NFILES])() = {
lxpr_read_invalid, /* /proc/sys/net/core */
lxpr_read_sys_net_core_somaxc, /* /proc/sys/net/core/somaxconn */
lxpr_read_invalid, /* /proc/sys/net/ipv4 */
+ lxpr_read_sys_net_ipv4_ip_lport_range, /* ../ipv4/ip_local_port_range */
lxpr_read_sys_net_ipv4_tcp_fin_to, /* .../ipv4/tcp_fin_timeout */
lxpr_read_sys_net_ipv4_tcp_ka_int, /* .../ipv4/tcp_keepalive_intvl */
lxpr_read_sys_net_ipv4_tcp_ka_tim, /* .../ipv4/tcp_keepalive_time */
@@ -806,6 +843,7 @@ static void (*lxpr_read_function[LXPR_NFILES])() = {
* Array of lookup functions, indexed by lx /proc file type.
*/
static vnode_t *(*lxpr_lookup_function[LXPR_NFILES])() = {
+ NULL, /* invalid */
lxpr_lookup_procdir, /* /proc */
lxpr_lookup_piddir, /* /proc/<pid> */
lxpr_lookup_not_a_dir, /* /proc/<pid>/auxv */
@@ -919,6 +957,7 @@ static vnode_t *(*lxpr_lookup_function[LXPR_NFILES])() = {
lxpr_lookup_sys_net_coredir, /* /proc/sys/net/core */
lxpr_lookup_not_a_dir, /* /proc/sys/net/core/somaxconn */
lxpr_lookup_sys_net_ipv4dir, /* /proc/sys/net/ipv4 */
+ lxpr_lookup_not_a_dir, /* .../net/ipv4/ip_local_port_range */
lxpr_lookup_not_a_dir, /* .../net/ipv4/tcp_fin_timeout */
lxpr_lookup_not_a_dir, /* .../net/ipv4/tcp_keepalive_intvl */
lxpr_lookup_not_a_dir, /* .../net/ipv4/tcp_keepalive_time */
@@ -939,6 +978,7 @@ static vnode_t *(*lxpr_lookup_function[LXPR_NFILES])() = {
* Array of readdir functions, indexed by /proc file type.
*/
static int (*lxpr_readdir_function[LXPR_NFILES])() = {
+ NULL, /* invalid */
lxpr_readdir_procdir, /* /proc */
lxpr_readdir_piddir, /* /proc/<pid> */
lxpr_readdir_not_a_dir, /* /proc/<pid>/auxv */
@@ -1052,6 +1092,7 @@ static int (*lxpr_readdir_function[LXPR_NFILES])() = {
lxpr_readdir_sys_net_coredir, /* /proc/sys/net/core */
lxpr_readdir_not_a_dir, /* /proc/sys/net/core/somaxconn */
lxpr_readdir_sys_net_ipv4dir, /* /proc/sys/net/ipv4 */
+ lxpr_readdir_not_a_dir, /* .../net/ipv4/ip_local_port_range */
lxpr_readdir_not_a_dir, /* .../net/ipv4/tcp_fin_timeout */
lxpr_readdir_not_a_dir, /* .../net/ipv4/tcp_keepalive_intvl */
lxpr_readdir_not_a_dir, /* .../net/ipv4/tcp_keepalive_time */
@@ -4560,6 +4601,35 @@ lxpr_read_sys_net_core_somaxc(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
}
/*
+ * ip_local_port_range
+ *
+ * The low & high port number range.
+ * integers; default: 32768 61000
+ *
+ * illumos: tcp_smallest_anon_port & tcp_largest_anon_port
+ * Not in tcp(7p) man page.
+ */
+static void
+lxpr_read_sys_net_ipv4_ip_lport_range(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+{
+ netstack_t *ns;
+ tcp_stack_t *tcps;
+
+ ASSERT(lxpnp->lxpr_type == LXPR_SYS_NET_IPV4_IP_LPORT_RANGE);
+
+ ns = netstack_get_current();
+ if (ns == NULL) {
+ lxpr_uiobuf_seterr(uiobuf, ENXIO);
+ return;
+ }
+
+ tcps = ns->netstack_tcp;
+ lxpr_uiobuf_printf(uiobuf, "%d\t%d\n",
+ tcps->tcps_smallest_anon_port, tcps->tcps_largest_anon_port);
+ netstack_rele(ns);
+}
+
+/*
* tcp_fin_timeout
*
* This specifies how many seconds to wait for a final FIN packet before the
@@ -5177,28 +5247,8 @@ lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
proc_t *tp;
/* lx /proc is primarily a read only file system */
- if (mode & VWRITE) {
- switch (type) {
- case LXPR_PID_LOGINUID:
- case LXPR_PID_OOM_SCR_ADJ:
- case LXPR_PID_TID_OOM_SCR_ADJ:
- case LXPR_SYS_KERNEL_COREPATT:
- case LXPR_SYS_KERNEL_SHMALL:
- case LXPR_SYS_KERNEL_SHMMAX:
- case LXPR_SYS_NET_CORE_SOMAXCON:
- case LXPR_SYS_NET_IPV4_TCP_FIN_TO:
- case LXPR_SYS_NET_IPV4_TCP_KA_INT:
- case LXPR_SYS_NET_IPV4_TCP_KA_TIM:
- case LXPR_SYS_NET_IPV4_TCP_SACK:
- case LXPR_SYS_NET_IPV4_TCP_WINSCALE:
- case LXPR_SYS_VM_OVERCOMMIT_MEM:
- case LXPR_SYS_VM_SWAPPINESS:
- case LXPR_PID_FD_FD:
- case LXPR_PID_TID_FD_FD:
- break;
- default:
- return (EROFS);
- }
+ if ((mode & VWRITE) && !lxpr_is_writable(type)) {
+ return (EROFS);
}
/*
@@ -6349,6 +6399,47 @@ lxpr_readdir_sys_vmdir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
SYS_VMDIRFILES));
}
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
+
+/*
+ * Obtain a numeric value from the null-terminated input string.
+ * We don't have strtok in the kernel, so tokenize this ourselves and
+ * validate the input.
+ */
+static int
+lxpr_tokenize_num(char *str, long *pv, char **ep)
+{
+ char *pstart, *pc, c, *endptr;
+ long v;
+
+ for (pc = str; isspace(*pc); pc++)
+ ;
+
+ for (pstart = pc; isdigit(*pc); pc++)
+ ;
+ if (pc == pstart || (!isspace(*pc) && *pc != '\0'))
+ return (EINVAL);
+ c = *pc;
+ *pc = '\0';
+
+ if (ddi_strtol(pstart, &endptr, 10, &v) != 0) {
+ *pc = c;
+ return (EINVAL);
+ }
+ if (*endptr != '\0') {
+ *pc = c;
+ return (EINVAL);
+ }
+
+ if (pv != NULL)
+ *pv = v;
+ if (ep != NULL)
+ *ep = ++pc;
+
+ return (0);
+}
+
/* ARGSUSED */
static int
lxpr_write_tcp_property(lxpr_node_t *lxpnp, struct uio *uio,
@@ -6415,11 +6506,11 @@ static int
lxpr_xlate_sec2ms(char *val, int size)
{
long sec;
- char *endptr = NULL;
+ char *ep;
- if (ddi_strtol(val, &endptr, 10, &sec) != 0)
+ if (lxpr_tokenize_num(val, &sec, &ep) != 0)
return (EINVAL);
- if (val[0] < '0' || val[0] > '9' || *endptr != '\0')
+ if (*ep != '\0')
return (EINVAL);
if (snprintf(val, size, "%ld", sec * 1000) >= size)
return (EINVAL);
@@ -6430,11 +6521,11 @@ static int
lxpr_xlate_ka_intvl(char *val, int size)
{
long sec;
- char *endptr = NULL;
+ char *ep;
- if (ddi_strtol(val, &endptr, 10, &sec) != 0)
+ if (lxpr_tokenize_num(val, &sec, &ep) != 0)
return (EINVAL);
- if (val[0] < '0' || val[0] > '9' || *endptr != '\0')
+ if (*ep != '\0')
return (EINVAL);
if (snprintf(val, size, "%ld", sec * 1000 * 9) >= size)
return (EINVAL);
@@ -6445,11 +6536,11 @@ static int
lxpr_xlate_sack(char *val, int size)
{
long flag;
- char *endptr = NULL;
+ char *ep;
- if (ddi_strtol(val, &endptr, 10, &flag) != 0)
+ if (lxpr_tokenize_num(val, &flag, &ep) != 0)
return (EINVAL);
- if (val[0] < '0' || val[0] > '9' || *endptr != '\0')
+ if (*ep != '\0')
return (EINVAL);
if (flag != 0 && flag != 1)
return (EINVAL);
@@ -6459,6 +6550,86 @@ lxpr_xlate_sack(char *val, int size)
return (0);
}
+/*
+ * We expect two port numbers on a line as input for the range, and we have to
+ * set two properties on the netstack_tcp, so we can't reuse
+ * lxpr_write_tcp_property.
+ */
+static int
+lxpr_write_sys_net_ipv4_ip_lport_range(lxpr_node_t *lxpnp, struct uio *uio,
+ struct cred *cr, caller_context_t *ct)
+{
+ int res;
+ size_t olen;
+ char vals[32]; /* big enough for a line w/ 2 16-bit numeric strings */
+ char *ep;
+ long low, high;
+ netstack_t *ns;
+ tcp_stack_t *tcps;
+ mod_prop_info_t *ptbl = NULL;
+ mod_prop_info_t *pinfo = NULL;
+
+ ASSERT(lxpnp->lxpr_type == LXPR_SYS_NET_IPV4_IP_LPORT_RANGE);
+
+ if (uio->uio_loffset != 0)
+ return (EINVAL);
+
+ if (uio->uio_resid == 0)
+ return (0);
+
+ olen = uio->uio_resid;
+ if (olen > sizeof (vals) - 1)
+ return (EINVAL);
+
+ bzero(vals, sizeof (vals));
+ res = uiomove(vals, olen, UIO_WRITE, uio);
+ if (res != 0)
+ return (res);
+
+ if (lxpr_tokenize_num(vals, &low, &ep) != 0)
+ return (EINVAL);
+
+ if (lxpr_tokenize_num(ep, &high, &ep) != 0)
+ return (EINVAL);
+
+ if (*ep != '\0') {
+ /* make sure no other tokens on the line */
+ *ep++ = '\0';
+ for (; isspace(*ep); ep++)
+ ;
+ if (*ep != '\0')
+ return (EINVAL);
+ }
+
+ if (low > high || high > 65535)
+ return (EINVAL);
+
+ ns = netstack_get_current();
+ if (ns == NULL)
+ return (EINVAL);
+
+ tcps = ns->netstack_tcp;
+ if (low < tcps->tcps_smallest_nonpriv_port) {
+ netstack_rele(ns);
+ return (EINVAL);
+ }
+
+ ptbl = ns->netstack_tcp->tcps_propinfo_tbl;
+
+ (void) snprintf(vals, sizeof (vals), "%ld", low);
+ pinfo = mod_prop_lookup(ptbl, "smallest_anon_port", MOD_PROTO_TCP);
+ if (pinfo == NULL || pinfo->mpi_setf(ns, cr, pinfo, NULL, vals, 0) != 0)
+ res = EINVAL;
+
+ (void) snprintf(vals, sizeof (vals), "%ld", high);
+ pinfo = mod_prop_lookup(ptbl, "largest_anon_port", MOD_PROTO_TCP);
+ if (pinfo == NULL || pinfo->mpi_setf(ns, cr, pinfo, NULL, vals, 0) != 0)
+ res = EINVAL;
+
+ netstack_rele(ns);
+ return (res);
+}
+
static int
lxpr_write_sys_net_ipv4_tcp_fin_to(lxpr_node_t *lxpnp, struct uio *uio,
struct cred *cr, caller_context_t *ct)
@@ -6573,7 +6744,7 @@ lxpr_write_pid_loginuid(lxpr_node_t *lxpnp, struct uio *uio, struct cred *cr,
int error;
size_t olen;
char val[16]; /* big enough for a uint numeric string */
- char *endptr = NULL;
+ char *ep;
long u;
proc_t *p;
lx_proc_data_t *pd;
@@ -6595,15 +6766,9 @@ lxpr_write_pid_loginuid(lxpr_node_t *lxpnp, struct uio *uio, struct cred *cr,
if (error != 0)
return (error);
- if (val[olen - 1] == '\n')
- val[olen - 1] = '\0';
-
- if (val[0] == '\0') /* no input */
- return (EINVAL);
-
- if (ddi_strtol(val, &endptr, 10, &u) != 0)
+ if (lxpr_tokenize_num(val, &u, &ep) != 0)
return (EINVAL);
- if (val[0] < '0' || val[0] > '9' || *endptr != '\0')
+ if (*ep != '\0')
return (EINVAL);
if ((p = lxpr_lock(lxpnp->lxpr_pid, NO_ZOMB)) == NULL)
@@ -6778,35 +6943,21 @@ lxpr_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
{
lxpr_node_t *lxpnp = VTOLXP(vp);
lxpr_nodetype_t type = lxpnp->lxpr_type;
+ int i;
- switch (type) {
- case LXPR_PID_LOGINUID:
- return (lxpr_write_pid_loginuid(lxpnp, uiop, cr, ct));
- case LXPR_SYS_KERNEL_COREPATT:
- return (lxpr_write_sys_kernel_corepatt(lxpnp, uiop, cr, ct));
- case LXPR_SYS_NET_CORE_SOMAXCON:
- return (lxpr_write_sys_net_core_somaxc(lxpnp, uiop, cr, ct));
- case LXPR_SYS_NET_IPV4_TCP_FIN_TO:
- return (lxpr_write_sys_net_ipv4_tcp_fin_to(lxpnp, uiop, cr,
- ct));
- case LXPR_SYS_NET_IPV4_TCP_KA_INT:
- return (lxpr_write_sys_net_ipv4_tcp_ka_int(lxpnp, uiop, cr,
- ct));
- case LXPR_SYS_NET_IPV4_TCP_KA_TIM:
- return (lxpr_write_sys_net_ipv4_tcp_ka_tim(lxpnp, uiop, cr,
- ct));
- case LXPR_SYS_NET_IPV4_TCP_SACK:
- return (lxpr_write_sys_net_ipv4_tcp_sack(lxpnp, uiop, cr, ct));
- case LXPR_SYS_NET_IPV4_TCP_WINSCALE:
- return (lxpr_write_sys_net_ipv4_tcp_winscale(lxpnp, uiop, cr,
- ct));
-
- default:
- /* pretend we wrote the whole thing */
- uiop->uio_offset += uiop->uio_resid;
- uiop->uio_resid = 0;
- return (0);
+ for (i = 0; wr_tab[i].wft_type != LXPR_INVALID; i++) {
+ if (wr_tab[i].wft_type == type) {
+ if (wr_tab[i].wft_wrf != NULL) {
+ return (wr_tab[i].wft_wrf(lxpnp, uiop, cr, ct));
+ }
+ break;
+ }
}
+
+ /* pretend we wrote the whole thing */
+ uiop->uio_offset += uiop->uio_resid;
+ uiop->uio_resid = 0;
+ return (0);
}
/* Needed for writable files which are first "truncated" */
@@ -6820,13 +6971,13 @@ lxpr_space(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset,
}
/*
- * We need to allow open with O_CREAT for the oom_score_adj file.
+ * We need to allow open with O_CREAT for the writable files.
*/
/*ARGSUSED7*/
static int
-lxpr_create(struct vnode *dvp, char *nm, struct vattr *vap,
- enum vcexcl exclusive, int mode, struct vnode **vpp, struct cred *cred,
- int flag, caller_context_t *ct, vsecattr_t *vsecp)
+lxpr_create(vnode_t *dvp, char *nm, vattr_t *vap, enum vcexcl exclusive,
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
lxpr_node_t *lxpnp = VTOLXP(dvp);
lxpr_nodetype_t type = lxpnp->lxpr_type;
@@ -6838,7 +6989,7 @@ lxpr_create(struct vnode *dvp, char *nm, struct vattr *vap,
/*
* restrict create permission to owner or root
*/
- if ((error = lxpr_access(dvp, VEXEC, 0, cred, ct)) != 0) {
+ if ((error = lxpr_access(dvp, VEXEC, 0, cr, ct)) != 0) {
return (error);
}
@@ -6852,73 +7003,23 @@ lxpr_create(struct vnode *dvp, char *nm, struct vattr *vap,
return (EEXIST);
/*
- * We're currently restricting O_CREAT to:
- * - /proc/<pid>/fd/<num>
- * - /proc/<pid>/oom_score_adj
- * - /proc/<pid>/task/<tid>/fd/<num>
- * - /proc/<pid>/task/<tid>/oom_score_adj
- * - /proc/sys/kernel/core_pattern
- * - /proc/sys/kernel/shmall
- * - /proc/sys/kernel/shmmax
- * - /proc/sys/net/core/somaxconn
- * - /proc/sys/vm/overcommit_memory
- * - /proc/sys/vm/swappiness
+ * No writable files in top-level proc dir. We check this to avoid
+ * getting a non-proc node via "..".
*/
- switch (type) {
- case LXPR_PIDDIR:
- case LXPR_PID_TASK_IDDIR:
- if (strcmp(nm, "oom_score_adj") == 0) {
- proc_t *p;
- p = lxpr_lock(lxpnp->lxpr_pid, ZOMB_OK);
- if (p != NULL) {
- vp = lxpr_lookup_common(dvp, nm, p, piddir,
- PIDDIRFILES);
- }
- lxpr_unlock(p);
- }
- break;
-
- case LXPR_SYS_NET_COREDIR:
- if (strcmp(nm, "somaxconn") == 0) {
- vp = lxpr_lookup_common(dvp, nm, NULL, sys_net_coredir,
- SYS_NET_COREDIRFILES);
- }
- break;
-
- case LXPR_SYS_KERNELDIR:
- if (strcmp(nm, "core_pattern") == 0 ||
- strcmp(nm, "shmall") == 0 ||
- strcmp(nm, "shmmax") == 0) {
- vp = lxpr_lookup_common(dvp, nm, NULL, sys_kerneldir,
- SYS_KERNELDIRFILES);
- }
- break;
-
- case LXPR_SYS_VMDIR:
- if (strcmp(nm, "overcommit_memory") == 0 ||
- strcmp(nm, "swappiness") == 0) {
- vp = lxpr_lookup_common(dvp, nm, NULL, sys_vmdir,
- SYS_VMDIRFILES);
+ if (type != LXPR_PROCDIR &&
+ lxpr_lookup(dvp, nm, &vp, NULL, 0, NULL, cr, ct, NULL, NULL) == 0) {
+ lxpr_nodetype_t ftype = VTOLXP(vp)->lxpr_type;
+ if (!lxpr_is_writable(ftype)) {
+ VN_RELE(vp);
+ vp = NULL;
}
- break;
-
- case LXPR_PID_FDDIR:
- case LXPR_PID_TID_FDDIR:
- vp = lxpr_lookup_fdnode(dvp, nm);
- break;
-
- default:
- vp = NULL;
- break;
}
if (vp != NULL) {
- /* Creating an existing file, allow it for regular files. */
- if (vp->v_type == VDIR)
- return (EISDIR);
+ ASSERT(vp->v_type != VDIR);
/* confirm permissions against existing file */
- if ((error = lxpr_access(vp, mode, 0, cred, ct)) != 0) {
+ if ((error = lxpr_access(vp, mode, 0, cr, ct)) != 0) {
VN_RELE(vp);
return (error);
}