@@ -132,6 +132,36 @@ int setns(int fd, int nstype)
132132}
133133#endif
134134
135+ /*
136+ * CHECK_IO calls op (read or write) and checks its return value.
137+ * If a syscall returns -1 (error), it calls bail() to report errno.
138+ * Otherwise, check for a short read/write and call bailx() on error.
139+ */
140+ #define CHECK_IO (op , fd , buf , count , ...) \
141+ do { \
142+ ssize_t __ret = op(fd, buf, count); \
143+ if (__ret < 0) \
144+ bail(__VA_ARGS__); \
145+ if (__ret != (ssize_t)(count)) \
146+ bailx(__VA_ARGS__ ": short " #op); \
147+ } while (0)
148+
149+ /*
150+ * CHECK_IO_KILL is a variant of CHECK_IO that kills PIDs before bailing.
151+ * Use this when you need to kill child process(es) on I/O failure.
152+ */
153+ #define CHECK_IO_KILL (op , fd , buf , count , pid1 , pid2 , ...) \
154+ do { \
155+ ssize_t __ret = op(fd, buf, count); \
156+ if (__ret != (ssize_t)(count)) { \
157+ sane_kill(pid1, SIGKILL); \
158+ sane_kill(pid2, SIGKILL); \
159+ if (__ret < 0) \
160+ bail(__VA_ARGS__); \
161+ bailx(__VA_ARGS__ ": short " #op); \
162+ } \
163+ } while (0)
164+
135165/* XXX: This is ugly. */
136166static int syncfd = -1 ;
137167
@@ -334,16 +364,12 @@ static uint8_t readint8(char *buf)
334364
335365static void nl_parse (int fd , struct nlconfig_t * config )
336366{
337- size_t len , size ;
367+ size_t size ;
338368 struct nlmsghdr hdr ;
339369 char * data , * current ;
340370
341371 /* 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 );
372+ CHECK_IO (read , fd , & hdr , NLMSG_HDRLEN , "failed to read netlink header" );
347373
348374 if (hdr .nlmsg_type == NLMSG_ERROR )
349375 bailx ("failed to read netlink message" );
@@ -357,11 +383,7 @@ static void nl_parse(int fd, struct nlconfig_t *config)
357383 if (!data )
358384 bail ("failed to allocate %zu bytes of memory for nl_payload" , size );
359385
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 );
386+ CHECK_IO (read , fd , data , size , "failed to read netlink payload" );
365387
366388 /* Parse the netlink payload. */
367389 config -> data = data ;
@@ -863,8 +885,7 @@ void nsexec(void)
863885 while (!stage1_complete ) {
864886 enum sync_t s ;
865887
866- if (read (syncfd , & s , sizeof (s )) != sizeof (s ))
867- bail ("failed to sync with stage-1: next state" );
888+ CHECK_IO (read , syncfd , & s , sizeof (s ), "failed to sync with stage-1: next state" );
868889
869890 switch (s ) {
870891 case SYNC_USERMAP_PLS :
@@ -888,28 +909,20 @@ void nsexec(void)
888909 update_gidmap (config .gidmappath , stage1_pid , config .gidmap , config .gidmap_len );
889910
890911 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- }
912+ CHECK_IO_KILL (write , syncfd , & s , sizeof (s ), stage1_pid , stage2_pid ,
913+ "failed to sync with stage-1: write(SYNC_USERMAP_ACK)" );
896914 break ;
897915 case SYNC_RECVPID_PLS :
898916 write_log (DEBUG , "stage-1 requested pid to be forwarded" );
899917
900918 /* 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- }
919+ CHECK_IO_KILL (read , syncfd , & stage2_pid , sizeof (stage2_pid ), stage1_pid , -1 ,
920+ "failed to sync with stage-1: read(stage2_pid)" );
905921
906922 /* Send ACK. */
907923 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- }
924+ CHECK_IO_KILL (write , syncfd , & s , sizeof (s ), stage1_pid , stage2_pid ,
925+ "failed to sync with stage-1: write(SYNC_RECVPID_ACK)" );
913926
914927 /*
915928 * Send both the stage-1 and stage-2 pids back to runc.
@@ -933,10 +946,8 @@ void nsexec(void)
933946 write_log (DEBUG , "stage-1 requested timens offsets to be configured" );
934947 update_timens_offsets (stage1_pid , config .timensoffset , config .timensoffset_len );
935948 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- }
949+ CHECK_IO_KILL (write , syncfd , & s , sizeof (s ), stage1_pid , -1 ,
950+ "failed to sync with child: write(SYNC_TIMEOFFSETS_ACK)" );
940951 break ;
941952 case SYNC_CHILD_FINISH :
942953 write_log (DEBUG , "stage-1 complete" );
@@ -960,13 +971,10 @@ void nsexec(void)
960971
961972 write_log (DEBUG , "signalling stage-2 to run" );
962973 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- }
974+ CHECK_IO_KILL (write , syncfd , & s , sizeof (s ), stage2_pid , -1 ,
975+ "failed to sync with child: write(SYNC_GRANDCHILD)" );
967976
968- if (read (syncfd , & s , sizeof (s )) != sizeof (s ))
969- bail ("failed to sync with child: next state" );
977+ CHECK_IO (read , syncfd , & s , sizeof (s ), "failed to sync with child: next state" );
970978
971979 switch (s ) {
972980 case SYNC_CHILD_FINISH :
@@ -1057,13 +1065,13 @@ void nsexec(void)
10571065 */
10581066 write_log (DEBUG , "request stage-0 to map user namespace" );
10591067 s = SYNC_USERMAP_PLS ;
1060- if (write ( syncfd , & s , sizeof (s )) != sizeof ( s ))
1061- bail ( "failed to sync with parent: write(SYNC_USERMAP_PLS)" );
1068+ CHECK_IO (write , syncfd , & s , sizeof (s ),
1069+ "failed to sync with parent: write(SYNC_USERMAP_PLS)" );
10621070
10631071 /* ... wait for mapping ... */
10641072 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)" );
1073+ CHECK_IO (read , syncfd , & s , sizeof (s ),
1074+ "failed to sync with parent: read(SYNC_USERMAP_ACK)" );
10671075 if (s != SYNC_USERMAP_ACK )
10681076 bailx ("failed to sync with parent: SYNC_USERMAP_ACK: got %u" , s );
10691077
@@ -1095,11 +1103,11 @@ void nsexec(void)
10951103 write_log (DEBUG , "request stage-0 to write timens offsets" );
10961104
10971105 s = SYNC_TIMEOFFSETS_PLS ;
1098- if (write ( syncfd , & s , sizeof (s )) != sizeof ( s ))
1099- bail ( "failed to sync with parent: write(SYNC_TIMEOFFSETS_PLS)" );
1106+ CHECK_IO (write , syncfd , & s , sizeof (s ),
1107+ "failed to sync with parent: write(SYNC_TIMEOFFSETS_PLS)" );
11001108
1101- if (read ( syncfd , & s , sizeof (s )) != sizeof ( s ))
1102- bail ( "failed to sync with parent: read(SYNC_TIMEOFFSETS_ACK)" );
1109+ CHECK_IO (read , syncfd , & s , sizeof (s ),
1110+ "failed to sync with parent: read(SYNC_TIMEOFFSETS_ACK)" );
11031111 if (s != SYNC_TIMEOFFSETS_ACK )
11041112 bailx ("failed to sync with parent: SYNC_TIMEOFFSETS_ACK: got %u" , s );
11051113 }
@@ -1121,31 +1129,23 @@ void nsexec(void)
11211129 /* Send the child to our parent, which knows what it's doing. */
11221130 write_log (DEBUG , "request stage-0 to forward stage-2 pid (%d)" , stage2_pid );
11231131 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- }
1132+ CHECK_IO_KILL (write , syncfd , & s , sizeof (s ), stage2_pid , -1 ,
1133+ "failed to sync with parent: write(SYNC_RECVPID_PLS)" );
1134+ CHECK_IO_KILL (write , syncfd , & stage2_pid , sizeof (stage2_pid ), stage2_pid , -1 ,
1135+ "failed to sync with parent: write(stage2_pid)" );
11321136
11331137 /* ... 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- }
1138+ CHECK_IO_KILL (read , syncfd , & s , sizeof (s ), stage2_pid , -1 ,
1139+ "failed to sync with parent: read(SYNC_RECVPID_ACK)" );
11381140 if (s != SYNC_RECVPID_ACK ) {
11391141 sane_kill (stage2_pid , SIGKILL );
11401142 bailx ("failed to sync with parent: SYNC_RECVPID_ACK: got %u" , s );
11411143 }
11421144
11431145 write_log (DEBUG , "signal completion to stage-0" );
11441146 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- }
1147+ CHECK_IO_KILL (write , syncfd , & s , sizeof (s ), stage2_pid , -1 ,
1148+ "failed to sync with parent: write(SYNC_CHILD_FINISH)" );
11491149
11501150 /* Our work is done. [Stage 2: STAGE_INIT] is doing the rest of the work. */
11511151 write_log (DEBUG , "<~ nsexec stage-1" );
@@ -1181,8 +1181,7 @@ void nsexec(void)
11811181 prctl (PR_SET_NAME , (unsigned long )"runc:[2:INIT]" , 0 , 0 , 0 );
11821182 write_log (DEBUG , "~> nsexec stage-2" );
11831183
1184- if (read (syncfd , & s , sizeof (s )) != sizeof (s ))
1185- bail ("failed to sync with parent: read(SYNC_GRANDCHILD)" );
1184+ CHECK_IO (read , syncfd , & s , sizeof (s ), "failed to sync with parent: read(SYNC_GRANDCHILD)" );
11861185 if (s != SYNC_GRANDCHILD )
11871186 bailx ("failed to sync with parent: SYNC_GRANDCHILD: got %u" , s );
11881187
@@ -1202,8 +1201,7 @@ void nsexec(void)
12021201
12031202 write_log (DEBUG , "signal completion to stage-0" );
12041203 s = SYNC_CHILD_FINISH ;
1205- if (write (syncfd , & s , sizeof (s )) != sizeof (s ))
1206- bail ("failed to sync with parent: write(SYNC_CHILD_FINISH)" );
1204+ CHECK_IO (write , syncfd , & s , sizeof (s ), "failed to sync with parent: write(SYNC_CHILD_FINISH)" );
12071205
12081206 /* Close sync pipes. */
12091207 if (close (sync_grandchild_pipe [0 ]) < 0 )
0 commit comments