@@ -71,108 +71,119 @@ struct psr_ctx {
7171 struct psr_error psr_error ;
7272 size_t psr_datalen ;
7373 void * psr_data ;
74- size_t psr_mdatalen ;
75- void * psr_mdata ;
76- bool psr_usemdata ;
74+ bool psr_mallocdata ;
7775};
7876
7977static ssize_t
80- ps_root_readerrorcb (struct psr_ctx * psr_ctx )
78+ ps_root_readerrorcb (struct psr_ctx * pc )
8179{
82- struct dhcpcd_ctx * ctx = psr_ctx -> psr_ctx ;
80+ struct dhcpcd_ctx * ctx = pc -> psr_ctx ;
8381 int fd = PS_ROOT_FD (ctx );
84- struct psr_error * psr_error = & psr_ctx -> psr_error ;
82+ struct psr_error * psr_error = & pc -> psr_error ;
8583 struct iovec iov [] = {
8684 { .iov_base = psr_error , .iov_len = sizeof (* psr_error ) },
87- { .iov_base = NULL , .iov_len = 0 },
85+ { .iov_base = pc -> psr_data , .iov_len = pc -> psr_datalen },
8886 };
87+ struct msghdr msg = { .msg_iov = iov , .msg_iovlen = __arraycount (iov ) };
8988 ssize_t len ;
9089
9190#define PSR_ERROR (e ) \
9291 do { \
93- psr_error->psr_result = -1; \
9492 psr_error->psr_errno = (e); \
95- return -1 ; \
93+ goto error ; \
9694 } while (0 /* CONSTCOND */ )
9795
9896 if (eloop_waitfd (fd ) == -1 )
9997 PSR_ERROR (errno );
10098
101- len = recv (fd , psr_error , sizeof (* psr_error ), MSG_PEEK );
99+ if (!pc -> psr_mallocdata )
100+ goto recv ;
101+
102+ /* We peek at the psr_error structure to tell us how much of a buffer
103+ * we need to read the whole packet. */
104+ msg .msg_iovlen -- ;
105+ len = recvmsg (fd , & msg , MSG_PEEK | MSG_WAITALL );
102106 if (len == -1 )
103107 PSR_ERROR (errno );
104- else if ((size_t )len < sizeof (* psr_error ))
105- PSR_ERROR (EINVAL );
106108
107- if (psr_error -> psr_datalen > SSIZE_MAX )
108- PSR_ERROR (ENOBUFS );
109- if (psr_ctx -> psr_usemdata &&
110- psr_error -> psr_datalen > psr_ctx -> psr_mdatalen )
111- {
112- void * d = realloc (psr_ctx -> psr_mdata , psr_error -> psr_datalen );
113- if (d == NULL )
114- PSR_ERROR (errno );
115- psr_ctx -> psr_mdata = d ;
116- psr_ctx -> psr_mdatalen = psr_error -> psr_datalen ;
109+ /* After this point, we MUST do another recvmsg even on a failure
110+ * to remove the message after peeking. */
111+ if ((size_t )len < sizeof (* psr_error )) {
112+ /* We can't use the header to work out buffers, so
113+ * remove the message and bail. */
114+ (void )recvmsg (fd , & msg , MSG_WAITALL );
115+ PSR_ERROR (EINVAL );
117116 }
118- if ( psr_error -> psr_datalen != 0 ) {
119- if ( psr_ctx -> psr_usemdata )
120- iov [ 1 ]. iov_base = psr_ctx -> psr_mdata ;
121- else {
122- if ( psr_error -> psr_datalen > psr_ctx -> psr_datalen )
123- PSR_ERROR ( ENOBUFS );
124- iov [ 1 ]. iov_base = psr_ctx -> psr_data ;
125- }
117+
118+ /* No data to read? Unlikely but ... */
119+ if ( psr_error -> psr_datalen == 0 )
120+ goto recv ;
121+
122+ pc -> psr_data = malloc ( psr_error -> psr_datalen );
123+ if ( pc -> psr_data != NULL ) {
124+ iov [ 1 ]. iov_base = pc -> psr_data ;
126125 iov [1 ].iov_len = psr_error -> psr_datalen ;
126+ msg .msg_iovlen ++ ;
127127 }
128128
129- len = readv (fd , iov , __arraycount (iov ));
129+ recv :
130+ len = recvmsg (fd , & msg , MSG_WAITALL );
130131 if (len == -1 )
131132 PSR_ERROR (errno );
132- else if ((size_t )len != sizeof (* psr_error ) + psr_error -> psr_datalen )
133+ else if ((size_t )len < sizeof (* psr_error ))
133134 PSR_ERROR (EINVAL );
135+ else if (msg .msg_flags & MSG_TRUNC )
136+ PSR_ERROR (ENOBUFS );
137+ else if ((size_t )len != sizeof (* psr_error ) + psr_error -> psr_datalen ) {
138+ #ifdef PRIVSEP_DEBUG
139+ logerrx ("%s: recvmsg returned %zd, expecting %zu" , __func__ ,
140+ len , sizeof (* psr_error ) + psr_error -> psr_datalen );
141+ #endif
142+ PSR_ERROR (EBADMSG );
143+ }
134144 return len ;
145+
146+ error :
147+ psr_error -> psr_result = -1 ;
148+ if (pc -> psr_mallocdata && pc -> psr_data != NULL ) {
149+ free (pc -> psr_data );
150+ pc -> psr_data = NULL ;
151+ }
152+ return -1 ;
135153}
136154
137155ssize_t
138156ps_root_readerror (struct dhcpcd_ctx * ctx , void * data , size_t len )
139157{
140- struct psr_ctx * pc = ctx -> ps_root -> psp_data ;
158+ struct psr_ctx pc = {
159+ .psr_ctx = ctx ,
160+ .psr_data = data ,
161+ .psr_datalen = len ,
162+ .psr_mallocdata = false
163+ };
141164
142- pc -> psr_data = data ;
143- pc -> psr_datalen = len ;
144- pc -> psr_usemdata = false;
145- ps_root_readerrorcb (pc );
165+ ps_root_readerrorcb (& pc );
146166
147- errno = pc -> psr_error .psr_errno ;
148- return pc -> psr_error .psr_result ;
167+ errno = pc . psr_error .psr_errno ;
168+ return pc . psr_error .psr_result ;
149169}
150170
151171ssize_t
152172ps_root_mreaderror (struct dhcpcd_ctx * ctx , void * * data , size_t * len )
153173{
154- struct psr_ctx * pc = ctx -> ps_root -> psp_data ;
155- void * d ;
174+ struct psr_ctx pc = {
175+ .psr_ctx = ctx ,
176+ .psr_data = NULL ,
177+ .psr_datalen = 0 ,
178+ .psr_mallocdata = true
179+ };
156180
157- pc -> psr_usemdata = true;
158- ps_root_readerrorcb (pc );
181+ ps_root_readerrorcb (& pc );
159182
160- if (pc -> psr_error .psr_datalen != 0 ) {
161- if (pc -> psr_error .psr_datalen > pc -> psr_mdatalen ) {
162- errno = EINVAL ;
163- return -1 ;
164- }
165- d = malloc (pc -> psr_error .psr_datalen );
166- if (d == NULL )
167- return -1 ;
168- memcpy (d , pc -> psr_mdata , pc -> psr_error .psr_datalen );
169- } else
170- d = NULL ;
171-
172- errno = pc -> psr_error .psr_errno ;
173- * data = d ;
174- * len = pc -> psr_error .psr_datalen ;
175- return pc -> psr_error .psr_result ;
183+ errno = pc .psr_error .psr_errno ;
184+ * data = pc .psr_data ;
185+ * len = pc .psr_error .psr_datalen ;
186+ return pc .psr_error .psr_result ;
176187}
177188
178189static ssize_t
@@ -196,6 +207,8 @@ ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result,
196207 logdebugx ("%s: result %zd errno %d" , __func__ , result , errno );
197208#endif
198209
210+ if (len == 0 )
211+ msg .msg_iovlen = 1 ;
199212 err = sendmsg (fd , & msg , MSG_EOR );
200213
201214 /* Error sending the message? Try sending the error of sending. */
@@ -204,8 +217,8 @@ ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result,
204217 __func__ , result , data , len );
205218 psr .psr_result = err ;
206219 psr .psr_errno = errno ;
207- iov [ 1 ]. iov_base = NULL ;
208- iov [ 1 ]. iov_len = 0 ;
220+ psr . psr_datalen = 0 ;
221+ msg . msg_iovlen = 1 ;
209222 err = sendmsg (fd , & msg , MSG_EOR );
210223 }
211224
@@ -602,7 +615,7 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
602615 break ;
603616 }
604617
605- err = ps_root_writeerror (ctx , err , rlen != 0 ? rdata : 0 , rlen );
618+ err = ps_root_writeerror (ctx , err , rdata , rlen );
606619 if (free_rdata )
607620 free (rdata );
608621 return err ;
@@ -843,17 +856,6 @@ ps_root_log(void *arg, unsigned short events)
843856 logerr (__func__ );
844857}
845858
846- static void
847- ps_root_freepsdata (void * arg )
848- {
849- struct psr_ctx * pc = arg ;
850-
851- if (pc == NULL )
852- return ;
853- free (pc -> psr_mdata );
854- free (pc );
855- }
856-
857859pid_t
858860ps_root_start (struct dhcpcd_ctx * ctx )
859861{
@@ -864,7 +866,6 @@ ps_root_start(struct dhcpcd_ctx *ctx)
864866 struct ps_process * psp ;
865867 int logfd [2 ] = { -1 , -1 }, datafd [2 ] = { -1 , -1 };
866868 pid_t pid ;
867- struct psr_ctx * pc ;
868869
869870 if (xsocketpair (AF_UNIX , SOCK_SEQPACKET | SOCK_CXNB , 0 , logfd ) == -1 )
870871 return -1 ;
@@ -883,27 +884,15 @@ ps_root_start(struct dhcpcd_ctx *ctx)
883884 return -1 ;
884885#endif
885886
886- pc = calloc (1 , sizeof (* pc ));
887- if (pc == NULL )
888- return -1 ;
889- pc -> psr_ctx = ctx ;
890-
891887 psp = ctx -> ps_root = ps_newprocess (ctx , & id );
892888 if (psp == NULL )
893- {
894- free (pc );
895889 return -1 ;
896- }
897- psp -> psp_freedata = ps_root_freepsdata ;
890+
898891 strlcpy (psp -> psp_name , "privileged proxy" , sizeof (psp -> psp_name ));
899892 pid = ps_startprocess (psp , ps_root_recvmsg , NULL ,
900893 ps_root_startcb , PSF_ELOOP );
901- if (pid == -1 ) {
902- free (pc );
894+ if (pid == -1 )
903895 return -1 ;
904- }
905-
906- psp -> psp_data = pc ;
907896
908897 if (pid == 0 ) {
909898 ctx -> ps_log_fd = logfd [0 ]; /* Keep open to pass to processes */
0 commit comments