summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2024-01-22 16:18:07 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2024-01-22 16:18:07 +0000
commitbd92455fedfb4aca02bf0ee3cabc5ecc4a852a4d (patch)
tree7eddee18b845254548fd71cb218ece1ccc0fce06
parentbbc2551a91978838ac0cb42f9753d3c74d100b65 (diff)
When getpwnam(3) reaches out to YP, it calls clntudp_create(3) with a
pre-initialized ypconnect(2) socket. That calls clntudp_bufcreate(), which contains code checking if the socket and address are configured.. If not, socket(2) is called, or an address allocation is performed via the portmapper (which calls a whole lot more code). Split clnt_udp.c into two .c files (which will compile as seperate .o files), and create a new libc-private clntudp_bufcreate_simple() function which skips the socket and address work. Result: In most static binaries, this reduces the text segment by ~100K, and removes 5-7 system call stubs -- which might matter for non-pledged binaries with otherwise lack socket(2). ok millert jmatthew
-rw-r--r--lib/libc/rpc/Makefile.inc4
-rw-r--r--lib/libc/rpc/clnt_udp.c195
-rw-r--r--lib/libc/rpc/clnt_udp.h70
-rw-r--r--lib/libc/rpc/clnt_udp_bufcreate.c130
-rw-r--r--lib/libc/yp/yp_bind.c10
5 files changed, 296 insertions, 113 deletions
diff --git a/lib/libc/rpc/Makefile.inc b/lib/libc/rpc/Makefile.inc
index 940fa4157aa..f8b1f6339ab 100644
--- a/lib/libc/rpc/Makefile.inc
+++ b/lib/libc/rpc/Makefile.inc
@@ -1,11 +1,11 @@
-# $OpenBSD: Makefile.inc,v 1.18 2016/03/30 06:38:41 jmc Exp $
+# $OpenBSD: Makefile.inc,v 1.19 2024/01/22 16:18:06 deraadt Exp $
# librpc sources
.PATH: ${LIBCSRCDIR}/arch/${MACHINE}/rpc ${LIBCSRCDIR}/rpc
SRCS+= auth_none.c auth_unix.c authunix_prot.c bindresvport.c \
clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c clnt_tcp.c \
- clnt_udp.c get_myaddress.c getrpcent.c getrpcport.c \
+ clnt_udp.c clnt_udp_bufcreate.c get_myaddress.c getrpcent.c getrpcport.c \
pmap_clnt.c pmap_getmaps.c pmap_getport.c pmap_prot.c \
pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c rpc_callmsg.c \
svc.c svc_auth.c svc_auth_unix.c svc_raw.c svc_run.c svc_simple.c \
diff --git a/lib/libc/rpc/clnt_udp.c b/lib/libc/rpc/clnt_udp.c
index e40347be5c7..bcb5b35adf1 100644
--- a/lib/libc/rpc/clnt_udp.c
+++ b/lib/libc/rpc/clnt_udp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clnt_udp.c,v 1.40 2022/08/24 01:32:21 deraadt Exp $ */
+/* $OpenBSD: clnt_udp.c,v 1.41 2024/01/22 16:18:06 deraadt Exp $ */
/*
* Copyright (c) 2010, Oracle America, Inc.
@@ -44,7 +44,7 @@
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
-#include <rpc/pmap_clnt.h>
+#include "clnt_udp.h"
/*
* UDP bases client side rpc operations
@@ -66,31 +66,65 @@ static const struct clnt_ops udp_ops = {
clntudp_control
};
-/*
- * Private data kept per client handle
- */
-struct cu_data {
- int cu_sock;
- bool_t cu_closeit;
- struct sockaddr_in cu_raddr;
- int cu_connected; /* use send() instead */
- int cu_rlen;
- struct timeval cu_wait;
- struct timeval cu_total;
- struct rpc_err cu_error;
- XDR cu_outxdrs;
- u_int cu_xdrpos;
- u_int cu_sendsz;
- char *cu_outbuf;
- u_int cu_recvsz;
- char cu_inbuf[1];
-};
+int
+clntudp_bufcreate1(struct clntudp_bufcreate_args *args)
+{
+ args->cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
+ if (args->cl == NULL) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ return -1;
+ }
+ args->sendsz = ((args->sendsz + 3) / 4) * 4;
+ args->recvsz = ((args->recvsz + 3) / 4) * 4;
+ args->cu = (struct cu_data *)mem_alloc(sizeof(args->cu) +
+ args->sendsz + args->recvsz);
+ if (args->cu == NULL) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ return -1;
+ }
+ args->cu->cu_outbuf = &args->cu->cu_inbuf[args->recvsz];
+ args->cl->cl_ops = &udp_ops;
+ args->cl->cl_private = (caddr_t)args->cu;
+ args->cu->cu_connected = 0;
+ args->cu->cu_rlen = sizeof (args->cu->cu_raddr);
+ args->cu->cu_wait = args->wait;
+ args->cu->cu_total.tv_sec = -1;
+ args->cu->cu_total.tv_usec = -1;
+ args->cu->cu_sendsz = args->sendsz;
+ args->cu->cu_recvsz = args->recvsz;
+ args->cu->cu_closeit = FALSE;
+ args->call_msg.rm_xid = arc4random();
+ args->call_msg.rm_direction = CALL;
+ args->call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ args->call_msg.rm_call.cb_prog = args->program;
+ args->call_msg.rm_call.cb_vers = args->version;
+ return 0;
+}
+
+int
+clntudp_bufcreate2(struct clntudp_bufcreate_args *args)
+{
+ xdrmem_create(&(args->cu->cu_outxdrs), args->cu->cu_outbuf,
+ args->sendsz, XDR_ENCODE);
+ if (!xdr_callhdr(&(args->cu->cu_outxdrs), &args->call_msg))
+ return -1;
+ args->cu->cu_xdrpos = XDR_GETPOS(&(args->cu->cu_outxdrs));
+ args->cl->cl_auth = authnone_create();
+ if (args->cl->cl_auth == NULL) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ return -1;
+ }
+ return 0;
+}
/*
* Create a UDP based client handle.
- * If *sockp<0, *sockp is set to a newly created UPD socket.
+ * If *sockp<0, *sockp is set to a newly created UPD socket. (***)
* If raddr->sin_port is 0 a binder on the remote machine
- * is consulted for the correct port number.
+ * is consulted for the correct port number. (***)
* NB: It is the client's responsibility to close *sockp, unless
* clntudp_bufcreate() was called with *sockp = -1 (so it created
* the socket), and CLNT_DESTROY() is used.
@@ -103,100 +137,45 @@ struct cu_data {
*
* sendsz and recvsz are the maximum allowable packet sizes that can be
* sent and received.
+ *
+ * This is a reduced-functionality version of clntudp_bufcreate() that
+ * does not allocate socket or binding (***, above).
+ * The official function clntudp_bufcreate(), which does perform those
+ * two steps, is in clnt_udp_bufcreate.c. This split avoids pulling
+ * socket / portmap related code into programs only using getpwent / YP code.
*/
+
CLIENT *
-clntudp_bufcreate(struct sockaddr_in *raddr, u_long program, u_long version,
+clntudp_bufcreate_simple(struct sockaddr_in *raddr, u_long program, u_long version,
struct timeval wait, int *sockp, u_int sendsz, u_int recvsz)
{
- CLIENT *cl;
- struct cu_data *cu = NULL;
- struct rpc_msg call_msg;
-
- cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
- if (cl == NULL) {
- rpc_createerr.cf_stat = RPC_SYSTEMERROR;
- rpc_createerr.cf_error.re_errno = errno;
+ struct clntudp_bufcreate_args args;
+
+ args.raddr = raddr;
+ args.program = program;
+ args.version = version;
+ args.wait = wait;
+ args.sockp = sockp;
+ args.sendsz = sendsz;
+ args.recvsz = recvsz;
+ args.cl = NULL;
+ args.cu = NULL;
+
+ if (clntudp_bufcreate1(&args) == -1)
goto fooy;
- }
- sendsz = ((sendsz + 3) / 4) * 4;
- recvsz = ((recvsz + 3) / 4) * 4;
- cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
- if (cu == NULL) {
- rpc_createerr.cf_stat = RPC_SYSTEMERROR;
- rpc_createerr.cf_error.re_errno = errno;
+ args.cu->cu_raddr = *raddr;
+ args.cu->cu_sock = *sockp;
+ if (clntudp_bufcreate2(&args) == -1)
goto fooy;
- }
- cu->cu_outbuf = &cu->cu_inbuf[recvsz];
-
- if (raddr->sin_port == 0) {
- u_short port;
- if ((port =
- pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
- goto fooy;
- }
- raddr->sin_port = htons(port);
- }
- cl->cl_ops = &udp_ops;
- cl->cl_private = (caddr_t)cu;
- cu->cu_raddr = *raddr;
- cu->cu_connected = 0;
- cu->cu_rlen = sizeof (cu->cu_raddr);
- cu->cu_wait = wait;
- cu->cu_total.tv_sec = -1;
- cu->cu_total.tv_usec = -1;
- cu->cu_sendsz = sendsz;
- cu->cu_recvsz = recvsz;
- call_msg.rm_xid = arc4random();
- call_msg.rm_direction = CALL;
- call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
- call_msg.rm_call.cb_prog = program;
- call_msg.rm_call.cb_vers = version;
- xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
- sendsz, XDR_ENCODE);
- if (!xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
- goto fooy;
- }
- cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
- if (*sockp < 0) {
- *sockp = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK,
- IPPROTO_UDP);
- if (*sockp == -1) {
- rpc_createerr.cf_stat = RPC_SYSTEMERROR;
- rpc_createerr.cf_error.re_errno = errno;
- goto fooy;
- }
- /* attempt to bind to priv port */
- (void)bindresvport(*sockp, NULL);
- cu->cu_closeit = TRUE;
- } else {
- cu->cu_closeit = FALSE;
- }
- cu->cu_sock = *sockp;
- cl->cl_auth = authnone_create();
- if (cl->cl_auth == NULL) {
- rpc_createerr.cf_stat = RPC_SYSTEMERROR;
- rpc_createerr.cf_error.re_errno = errno;
- goto fooy;
- }
- return (cl);
+ return (args.cl);
fooy:
- if (cu)
- mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
- if (cl)
- mem_free((caddr_t)cl, sizeof(CLIENT));
+ if (args.cu)
+ mem_free((caddr_t)args.cu,
+ sizeof(*args.cu) + args.sendsz + args.recvsz);
+ if (args.cl)
+ mem_free((caddr_t)args.cl, sizeof(CLIENT));
return (NULL);
}
-DEF_WEAK(clntudp_bufcreate);
-
-CLIENT *
-clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version,
- struct timeval wait, int *sockp)
-{
-
- return(clntudp_bufcreate(raddr, program, version, wait, sockp,
- UDPMSGSIZE, UDPMSGSIZE));
-}
-DEF_WEAK(clntudp_create);
static enum clnt_stat
clntudp_call(CLIENT *cl, /* client handle */
diff --git a/lib/libc/rpc/clnt_udp.h b/lib/libc/rpc/clnt_udp.h
new file mode 100644
index 00000000000..745540be945
--- /dev/null
+++ b/lib/libc/rpc/clnt_udp.h
@@ -0,0 +1,70 @@
+/* $OpenBSD: clnt_udp.h,v 1.1 2024/01/22 16:18:06 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Private data kept per client handle
+ */
+struct cu_data {
+ int cu_sock;
+ bool_t cu_closeit;
+ struct sockaddr_in cu_raddr;
+ int cu_connected; /* use send() instead */
+ int cu_rlen;
+ struct timeval cu_wait;
+ struct timeval cu_total;
+ struct rpc_err cu_error;
+ XDR cu_outxdrs;
+ u_int cu_xdrpos;
+ u_int cu_sendsz;
+ char *cu_outbuf;
+ u_int cu_recvsz;
+ char cu_inbuf[1];
+};
+
+struct clntudp_bufcreate_args {
+ struct sockaddr_in *raddr;
+ u_long program;
+ u_long version;
+ struct timeval wait;
+ int *sockp;
+ u_int sendsz;
+ u_int recvsz;
+ CLIENT *cl;
+ struct cu_data *cu;
+ struct rpc_msg call_msg;
+};
+
+__BEGIN_HIDDEN_DECLS
+extern int clntudp_bufcreate1(struct clntudp_bufcreate_args *);
+extern int clntudp_bufcreate2(struct clntudp_bufcreate_args *);
+__END_HIDDEN_DECLS
diff --git a/lib/libc/rpc/clnt_udp_bufcreate.c b/lib/libc/rpc/clnt_udp_bufcreate.c
new file mode 100644
index 00000000000..b112c8a1613
--- /dev/null
+++ b/lib/libc/rpc/clnt_udp_bufcreate.c
@@ -0,0 +1,130 @@
+/* $OpenBSD: clnt_udp_bufcreate.c,v 1.1 2024/01/22 16:18:06 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * clnt_udp.c, Implements a UDP/IP based, client side RPC.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <rpc/pmap_clnt.h>
+#include "clnt_udp.h"
+
+/*
+ * Create a UDP based client handle.
+ * If *sockp<0, *sockp is set to a newly created UPD socket.
+ * If raddr->sin_port is 0 a binder on the remote machine
+ * is consulted for the correct port number.
+ * NB: It is the client's responsibility to close *sockp, unless
+ * clntudp_bufcreate() was called with *sockp = -1 (so it created
+ * the socket), and CLNT_DESTROY() is used.
+ * NB: The rpch->cl_auth is initialized to null authentication.
+ * Caller may wish to set this something more useful.
+ *
+ * wait is the amount of time used between retransmitting a call if
+ * no response has been heard; retransmission occurs until the actual
+ * rpc call times out.
+ *
+ * sendsz and recvsz are the maximum allowable packet sizes that can be
+ * sent and received.
+ */
+
+CLIENT *
+clntudp_bufcreate(struct sockaddr_in *raddr, u_long program, u_long version,
+ struct timeval wait, int *sockp, u_int sendsz, u_int recvsz)
+{
+ struct clntudp_bufcreate_args args;
+
+ args.raddr = raddr;
+ args.program = program;
+ args.version = version;
+ args.wait = wait;
+ args.sockp = sockp;
+ args.sendsz = sendsz;
+ args.recvsz = recvsz;
+
+ if (clntudp_bufcreate1(&args) == -1)
+ goto fooy;
+
+ if (raddr->sin_port == 0) {
+ u_short port;
+ if ((port =
+ pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
+ goto fooy;
+ }
+ raddr->sin_port = htons(port);
+ }
+ args.cu->cu_raddr = *raddr;
+ if (*sockp < 0) {
+ *sockp = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK,
+ IPPROTO_UDP);
+ if (*sockp == -1) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ goto fooy;
+ }
+ /* attempt to bind to priv port */
+ (void)bindresvport(*sockp, NULL);
+ args.cu->cu_closeit = TRUE;
+ }
+ args.cu->cu_sock = *args.sockp;
+
+ if (clntudp_bufcreate2(&args) == -1)
+ goto fooy;
+ return (args.cl);
+fooy:
+ if (args.cu)
+ mem_free((caddr_t)args.cu,
+ sizeof(*args.cu) + args.sendsz + args.recvsz);
+ if (args.cl)
+ mem_free((caddr_t)args.cl, sizeof(CLIENT));
+ return (NULL);
+}
+DEF_WEAK(clntudp_bufcreate);
+
+CLIENT *
+clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version,
+ struct timeval wait, int *sockp)
+{
+
+ return(clntudp_bufcreate(raddr, program, version, wait, sockp,
+ UDPMSGSIZE, UDPMSGSIZE));
+}
+DEF_WEAK(clntudp_create);
diff --git a/lib/libc/yp/yp_bind.c b/lib/libc/yp/yp_bind.c
index af6775e96b8..d99a5962bdd 100644
--- a/lib/libc/yp/yp_bind.c
+++ b/lib/libc/yp/yp_bind.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: yp_bind.c,v 1.32 2022/08/02 16:59:29 deraadt Exp $ */
+/* $OpenBSD: yp_bind.c,v 1.33 2024/01/22 16:18:06 deraadt Exp $ */
/*
* Copyright (c) 1992, 1993, 1996 Theo de Raadt <deraadt@theos.com>
* All rights reserved.
@@ -46,6 +46,10 @@
char _yp_domain[HOST_NAME_MAX+1];
int _yplib_timeout = 10;
+extern CLIENT *
+clntudp_bufcreate_simple(struct sockaddr_in *raddr, u_long program, u_long version,
+ struct timeval wait, int *sockp, u_int sendsz, u_int recvsz);
+
int
_yp_dobind(const char *dom, struct dom_binding **ypdb)
{
@@ -72,8 +76,8 @@ again:
tv.tv_sec = _yplib_timeout / 2;
tv.tv_usec = 0;
- ypbinding->dom_client = clntudp_create(&ypbinding->dom_server_addr,
- YPPROG, YPVERS, tv, &ypbinding->dom_socket);
+ ypbinding->dom_client = clntudp_bufcreate_simple(&ypbinding->dom_server_addr,
+ YPPROG, YPVERS, tv, &ypbinding->dom_socket, UDPMSGSIZE, UDPMSGSIZE);
if (ypbinding->dom_client == NULL) {
close(ypbinding->dom_socket);
ypbinding->dom_socket = -1;