@@ -132,6 +132,42 @@ int setns(int fd, int nstype)
132132}
133133#endif
134134
135+ /*
136+ * Check the result of read(2) or write(2) system calls.
137+ * If the syscall returned -1 (error), call bail() to report errno.
138+ * Otherwise, if the actual bytes transferred differs from expected,
139+ * call bailx() since errno is not meaningful for short reads/writes.
140+ *
141+ * Usage: CHECK_IO(read, syncfd, &s, sizeof(s), "failed to sync with parent");
142+ */
143+ #define CHECK_IO (op , fd , buf , count , ...) \
144+ do { \
145+ ssize_t __ret = op(fd, buf, count); \
146+ if (__ret < 0) \
147+ bail(__VA_ARGS__); \
148+ if (__ret != (ssize_t)(count)) \
149+ bailx(__VA_ARGS__ ": short " #op); \
150+ } while (0)
151+
152+ /*
153+ * CHECK_IO variant that kills PIDs before bailing.
154+ * Use this when you need to clean up child processes on I/O failure.
155+ *
156+ * Usage: CHECK_IO_CLEANUP(write, syncfd, &s, sizeof(s), stage1_pid, stage2_pid,
157+ * "failed to sync");
158+ */
159+ #define CHECK_IO_CLEANUP (op , fd , buf , count , pid1 , pid2 , ...) \
160+ do { \
161+ ssize_t __ret = op(fd, buf, count); \
162+ if (__ret != (ssize_t)(count)) { \
163+ sane_kill(pid1, SIGKILL); \
164+ sane_kill(pid2, SIGKILL); \
165+ if (__ret < 0) \
166+ bail(__VA_ARGS__); \
167+ bailx(__VA_ARGS__ ": short " #op); \
168+ } \
169+ } while (0)
170+
135171/* XXX: This is ugly. */
136172static int syncfd = -1 ;
137173
@@ -334,16 +370,12 @@ static uint8_t readint8(char *buf)
334370
335371static void nl_parse (int fd , struct nlconfig_t * config )
336372{
337- size_t len , size ;
373+ size_t size ;
338374 struct nlmsghdr hdr ;
339375 char * data , * current ;
340376
341377 /* Retrieve the netlink header. */
342- len = read (fd , & hdr , NLMSG_HDRLEN );
343- if (len < 0 )
344- bail ("failed to read netlink header" );
345- if (len != NLMSG_HDRLEN )
346- bailx ("invalid netlink header length %zu" , len );
378+ CHECK_IO (read , fd , & hdr , NLMSG_HDRLEN , "failed to read netlink header" );
347379
348380 if (hdr .nlmsg_type == NLMSG_ERROR )
349381 bailx ("failed to read netlink message" );
@@ -357,11 +389,7 @@ static void nl_parse(int fd, struct nlconfig_t *config)
357389 if (!data )
358390 bail ("failed to allocate %zu bytes of memory for nl_payload" , size );
359391
360- len = read (fd , data , size );
361- if (len < 0 )
362- bail ("failed to read netlink payload" );
363- if (len != size )
364- bailx ("failed to read netlink payload, %zu != %zu" , len , size );
392+ CHECK_IO (read , fd , data , size , "failed to read netlink payload" );
365393
366394 /* Parse the netlink payload. */
367395 config -> data = data ;
@@ -863,8 +891,7 @@ void nsexec(void)
863891 while (!stage1_complete ) {
864892 enum sync_t s ;
865893
866- if (read (syncfd , & s , sizeof (s )) != sizeof (s ))
867- bail ("failed to sync with stage-1: next state" );
894+ CHECK_IO (read , syncfd , & s , sizeof (s ), "failed to sync with stage-1: next state" );
868895
869896 switch (s ) {
870897 case SYNC_USERMAP_PLS :
@@ -888,28 +915,20 @@ void nsexec(void)
888915 update_gidmap (config .gidmappath , stage1_pid , config .gidmap , config .gidmap_len );
889916
890917 s = SYNC_USERMAP_ACK ;
891- if (write (syncfd , & s , sizeof (s )) != sizeof (s )) {
892- sane_kill (stage1_pid , SIGKILL );
893- sane_kill (stage2_pid , SIGKILL );
894- bail ("failed to sync with stage-1: write(SYNC_USERMAP_ACK)" );
895- }
918+ CHECK_IO_CLEANUP (write , syncfd , & s , sizeof (s ), stage1_pid , stage2_pid ,
919+ "failed to sync with stage-1: write(SYNC_USERMAP_ACK)" );
896920 break ;
897921 case SYNC_RECVPID_PLS :
898922 write_log (DEBUG , "stage-1 requested pid to be forwarded" );
899923
900924 /* Get the stage-2 pid. */
901- if (read (syncfd , & stage2_pid , sizeof (stage2_pid )) != sizeof (stage2_pid )) {
902- sane_kill (stage1_pid , SIGKILL );
903- bail ("failed to sync with stage-1: read(stage2_pid)" );
904- }
925+ CHECK_IO_CLEANUP (read , syncfd , & stage2_pid , sizeof (stage2_pid ), stage1_pid , -1 ,
926+ "failed to sync with stage-1: read(stage2_pid)" );
905927
906928 /* Send ACK. */
907929 s = SYNC_RECVPID_ACK ;
908- if (write (syncfd , & s , sizeof (s )) != sizeof (s )) {
909- sane_kill (stage1_pid , SIGKILL );
910- sane_kill (stage2_pid , SIGKILL );
911- bail ("failed to sync with stage-1: write(SYNC_RECVPID_ACK)" );
912- }
930+ CHECK_IO_CLEANUP (write , syncfd , & s , sizeof (s ), stage1_pid , stage2_pid ,
931+ "failed to sync with stage-1: write(SYNC_RECVPID_ACK)" );
913932
914933 /*
915934 * Send both the stage-1 and stage-2 pids back to runc.
@@ -933,10 +952,8 @@ void nsexec(void)
933952 write_log (DEBUG , "stage-1 requested timens offsets to be configured" );
934953 update_timens_offsets (stage1_pid , config .timensoffset , config .timensoffset_len );
935954 s = SYNC_TIMEOFFSETS_ACK ;
936- if (write (syncfd , & s , sizeof (s )) != sizeof (s )) {
937- sane_kill (stage1_pid , SIGKILL );
938- bail ("failed to sync with child: write(SYNC_TIMEOFFSETS_ACK)" );
939- }
955+ CHECK_IO_CLEANUP (write , syncfd , & s , sizeof (s ), stage1_pid , -1 ,
956+ "failed to sync with child: write(SYNC_TIMEOFFSETS_ACK)" );
940957 break ;
941958 case SYNC_CHILD_FINISH :
942959 write_log (DEBUG , "stage-1 complete" );
@@ -960,13 +977,10 @@ void nsexec(void)
960977
961978 write_log (DEBUG , "signalling stage-2 to run" );
962979 s = SYNC_GRANDCHILD ;
963- if (write (syncfd , & s , sizeof (s )) != sizeof (s )) {
964- sane_kill (stage2_pid , SIGKILL );
965- bail ("failed to sync with child: write(SYNC_GRANDCHILD)" );
966- }
980+ CHECK_IO_CLEANUP (write , syncfd , & s , sizeof (s ), stage2_pid , -1 ,
981+ "failed to sync with child: write(SYNC_GRANDCHILD)" );
967982
968- if (read (syncfd , & s , sizeof (s )) != sizeof (s ))
969- bail ("failed to sync with child: next state" );
983+ CHECK_IO (read , syncfd , & s , sizeof (s ), "failed to sync with child: next state" );
970984
971985 switch (s ) {
972986 case SYNC_CHILD_FINISH :
@@ -1057,13 +1071,13 @@ void nsexec(void)
10571071 */
10581072 write_log (DEBUG , "request stage-0 to map user namespace" );
10591073 s = SYNC_USERMAP_PLS ;
1060- if (write ( syncfd , & s , sizeof (s )) != sizeof ( s ))
1061- bail ( "failed to sync with parent: write(SYNC_USERMAP_PLS)" );
1074+ CHECK_IO (write , syncfd , & s , sizeof (s ),
1075+ "failed to sync with parent: write(SYNC_USERMAP_PLS)" );
10621076
10631077 /* ... wait for mapping ... */
10641078 write_log (DEBUG , "waiting stage-0 to complete the mapping of user namespace" );
1065- if (read ( syncfd , & s , sizeof (s )) != sizeof ( s ))
1066- bail ( "failed to sync with parent: read(SYNC_USERMAP_ACK)" );
1079+ CHECK_IO (read , syncfd , & s , sizeof (s ),
1080+ "failed to sync with parent: read(SYNC_USERMAP_ACK)" );
10671081 if (s != SYNC_USERMAP_ACK )
10681082 bailx ("failed to sync with parent: SYNC_USERMAP_ACK: got %u" , s );
10691083
@@ -1095,11 +1109,11 @@ void nsexec(void)
10951109 write_log (DEBUG , "request stage-0 to write timens offsets" );
10961110
10971111 s = SYNC_TIMEOFFSETS_PLS ;
1098- if (write ( syncfd , & s , sizeof (s )) != sizeof ( s ))
1099- bail ( "failed to sync with parent: write(SYNC_TIMEOFFSETS_PLS)" );
1112+ CHECK_IO (write , syncfd , & s , sizeof (s ),
1113+ "failed to sync with parent: write(SYNC_TIMEOFFSETS_PLS)" );
11001114
1101- if (read ( syncfd , & s , sizeof (s )) != sizeof ( s ))
1102- bail ( "failed to sync with parent: read(SYNC_TIMEOFFSETS_ACK)" );
1115+ CHECK_IO (read , syncfd , & s , sizeof (s ),
1116+ "failed to sync with parent: read(SYNC_TIMEOFFSETS_ACK)" );
11031117 if (s != SYNC_TIMEOFFSETS_ACK )
11041118 bailx ("failed to sync with parent: SYNC_TIMEOFFSETS_ACK: got %u" , s );
11051119 }
@@ -1121,31 +1135,23 @@ void nsexec(void)
11211135 /* Send the child to our parent, which knows what it's doing. */
11221136 write_log (DEBUG , "request stage-0 to forward stage-2 pid (%d)" , stage2_pid );
11231137 s = SYNC_RECVPID_PLS ;
1124- if (write (syncfd , & s , sizeof (s )) != sizeof (s )) {
1125- sane_kill (stage2_pid , SIGKILL );
1126- bail ("failed to sync with parent: write(SYNC_RECVPID_PLS)" );
1127- }
1128- if (write (syncfd , & stage2_pid , sizeof (stage2_pid )) != sizeof (stage2_pid )) {
1129- sane_kill (stage2_pid , SIGKILL );
1130- bail ("failed to sync with parent: write(stage2_pid)" );
1131- }
1138+ CHECK_IO_CLEANUP (write , syncfd , & s , sizeof (s ), stage2_pid , -1 ,
1139+ "failed to sync with parent: write(SYNC_RECVPID_PLS)" );
1140+ CHECK_IO_CLEANUP (write , syncfd , & stage2_pid , sizeof (stage2_pid ), stage2_pid , -1 ,
1141+ "failed to sync with parent: write(stage2_pid)" );
11321142
11331143 /* ... wait for parent to get the pid ... */
1134- if (read (syncfd , & s , sizeof (s )) != sizeof (s )) {
1135- sane_kill (stage2_pid , SIGKILL );
1136- bail ("failed to sync with parent: read(SYNC_RECVPID_ACK)" );
1137- }
1144+ CHECK_IO_CLEANUP (read , syncfd , & s , sizeof (s ), stage2_pid , -1 ,
1145+ "failed to sync with parent: read(SYNC_RECVPID_ACK)" );
11381146 if (s != SYNC_RECVPID_ACK ) {
11391147 sane_kill (stage2_pid , SIGKILL );
11401148 bailx ("failed to sync with parent: SYNC_RECVPID_ACK: got %u" , s );
11411149 }
11421150
11431151 write_log (DEBUG , "signal completion to stage-0" );
11441152 s = SYNC_CHILD_FINISH ;
1145- if (write (syncfd , & s , sizeof (s )) != sizeof (s )) {
1146- sane_kill (stage2_pid , SIGKILL );
1147- bail ("failed to sync with parent: write(SYNC_CHILD_FINISH)" );
1148- }
1153+ CHECK_IO_CLEANUP (write , syncfd , & s , sizeof (s ), stage2_pid , -1 ,
1154+ "failed to sync with parent: write(SYNC_CHILD_FINISH)" );
11491155
11501156 /* Our work is done. [Stage 2: STAGE_INIT] is doing the rest of the work. */
11511157 write_log (DEBUG , "<~ nsexec stage-1" );
@@ -1181,8 +1187,7 @@ void nsexec(void)
11811187 prctl (PR_SET_NAME , (unsigned long )"runc:[2:INIT]" , 0 , 0 , 0 );
11821188 write_log (DEBUG , "~> nsexec stage-2" );
11831189
1184- if (read (syncfd , & s , sizeof (s )) != sizeof (s ))
1185- bail ("failed to sync with parent: read(SYNC_GRANDCHILD)" );
1190+ CHECK_IO (read , syncfd , & s , sizeof (s ), "failed to sync with parent: read(SYNC_GRANDCHILD)" );
11861191 if (s != SYNC_GRANDCHILD )
11871192 bailx ("failed to sync with parent: SYNC_GRANDCHILD: got %u" , s );
11881193
@@ -1202,8 +1207,7 @@ void nsexec(void)
12021207
12031208 write_log (DEBUG , "signal completion to stage-0" );
12041209 s = SYNC_CHILD_FINISH ;
1205- if (write (syncfd , & s , sizeof (s )) != sizeof (s ))
1206- bail ("failed to sync with parent: write(SYNC_CHILD_FINISH)" );
1210+ CHECK_IO (write , syncfd , & s , sizeof (s ), "failed to sync with parent: write(SYNC_CHILD_FINISH)" );
12071211
12081212 /* Close sync pipes. */
12091213 if (close (sync_grandchild_pipe [0 ]) < 0 )
0 commit comments