Skip to content

Commit

Permalink
When getpwnam(3) reaches out to YP, it calls clntudp_create(3) with a
Browse files Browse the repository at this point in the history
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
  • Loading branch information
deraadt committed Jan 22, 2024
1 parent 139761c commit 903e91b
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 113 deletions.
4 changes: 2 additions & 2 deletions lib/libc/rpc/Makefile.inc
Original file line number Diff line number Diff line change
@@ -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 \
Expand Down
195 changes: 87 additions & 108 deletions lib/libc/rpc/clnt_udp.c
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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 */
Expand Down
70 changes: 70 additions & 0 deletions lib/libc/rpc/clnt_udp.h
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 903e91b

Please sign in to comment.