@@ -235,6 +235,10 @@ struct seccomp_notif_addfd {
235235};
236236#endif
237237
238+ #ifndef SECCOMP_ADDFD_FLAG_SEND
239+ #define SECCOMP_ADDFD_FLAG_SEND (1UL << 1) /* Addfd and return it, atomically */
240+ #endif
241+
238242struct seccomp_notif_addfd_small {
239243 __u64 id ;
240244 char weird [4 ];
@@ -3959,7 +3963,7 @@ TEST(user_notification_addfd)
39593963{
39603964 pid_t pid ;
39613965 long ret ;
3962- int status , listener , memfd , fd ;
3966+ int status , listener , memfd , fd , nextfd ;
39633967 struct seccomp_notif_addfd addfd = {};
39643968 struct seccomp_notif_addfd_small small = {};
39653969 struct seccomp_notif_addfd_big big = {};
@@ -3968,25 +3972,34 @@ TEST(user_notification_addfd)
39683972 /* 100 ms */
39693973 struct timespec delay = { .tv_nsec = 100000000 };
39703974
3975+ /* There may be arbitrary already-open fds at test start. */
39713976 memfd = memfd_create ("test" , 0 );
39723977 ASSERT_GE (memfd , 0 );
3978+ nextfd = memfd + 1 ;
39733979
39743980 ret = prctl (PR_SET_NO_NEW_PRIVS , 1 , 0 , 0 , 0 );
39753981 ASSERT_EQ (0 , ret ) {
39763982 TH_LOG ("Kernel does not support PR_SET_NO_NEW_PRIVS!" );
39773983 }
39783984
3985+ /* fd: 4 */
39793986 /* Check that the basic notification machinery works */
39803987 listener = user_notif_syscall (__NR_getppid ,
39813988 SECCOMP_FILTER_FLAG_NEW_LISTENER );
3982- ASSERT_GE (listener , 0 );
3989+ ASSERT_EQ (listener , nextfd ++ );
39833990
39843991 pid = fork ();
39853992 ASSERT_GE (pid , 0 );
39863993
39873994 if (pid == 0 ) {
3995+ /* fds will be added and this value is expected */
39883996 if (syscall (__NR_getppid ) != USER_NOTIF_MAGIC )
39893997 exit (1 );
3998+
3999+ /* Atomic addfd+send is received here. Check it is a valid fd */
4000+ if (fcntl (syscall (__NR_getppid ), F_GETFD ) == -1 )
4001+ exit (1 );
4002+
39904003 exit (syscall (__NR_getppid ) != USER_NOTIF_MAGIC );
39914004 }
39924005
@@ -4028,14 +4041,14 @@ TEST(user_notification_addfd)
40284041
40294042 /* Verify we can set an arbitrary remote fd */
40304043 fd = ioctl (listener , SECCOMP_IOCTL_NOTIF_ADDFD , & addfd );
4031- EXPECT_GE (fd , 0 );
4044+ EXPECT_EQ (fd , nextfd ++ );
40324045 EXPECT_EQ (filecmp (getpid (), pid , memfd , fd ), 0 );
40334046
40344047 /* Verify we can set an arbitrary remote fd with large size */
40354048 memset (& big , 0x0 , sizeof (big ));
40364049 big .addfd = addfd ;
40374050 fd = ioctl (listener , SECCOMP_IOCTL_NOTIF_ADDFD_BIG , & big );
4038- EXPECT_GE (fd , 0 );
4051+ EXPECT_EQ (fd , nextfd ++ );
40394052
40404053 /* Verify we can set a specific remote fd */
40414054 addfd .newfd = 42 ;
@@ -4065,6 +4078,32 @@ TEST(user_notification_addfd)
40654078 ASSERT_EQ (ioctl (listener , SECCOMP_IOCTL_NOTIF_RECV , & req ), 0 );
40664079 ASSERT_EQ (addfd .id , req .id );
40674080
4081+ /* Verify we can do an atomic addfd and send */
4082+ addfd .newfd = 0 ;
4083+ addfd .flags = SECCOMP_ADDFD_FLAG_SEND ;
4084+ fd = ioctl (listener , SECCOMP_IOCTL_NOTIF_ADDFD , & addfd );
4085+ /*
4086+ * Child has earlier "low" fds and now 42, so we expect the next
4087+ * lowest available fd to be assigned here.
4088+ */
4089+ EXPECT_EQ (fd , nextfd ++ );
4090+ EXPECT_EQ (filecmp (getpid (), pid , memfd , fd ), 0 );
4091+
4092+ /*
4093+ * This sets the ID of the ADD FD to the last request plus 1. The
4094+ * notification ID increments 1 per notification.
4095+ */
4096+ addfd .id = req .id + 1 ;
4097+
4098+ /* This spins until the underlying notification is generated */
4099+ while (ioctl (listener , SECCOMP_IOCTL_NOTIF_ADDFD , & addfd ) != -1 &&
4100+ errno != - EINPROGRESS )
4101+ nanosleep (& delay , NULL );
4102+
4103+ memset (& req , 0 , sizeof (req ));
4104+ ASSERT_EQ (ioctl (listener , SECCOMP_IOCTL_NOTIF_RECV , & req ), 0 );
4105+ ASSERT_EQ (addfd .id , req .id );
4106+
40684107 resp .id = req .id ;
40694108 resp .error = 0 ;
40704109 resp .val = USER_NOTIF_MAGIC ;
@@ -4125,6 +4164,10 @@ TEST(user_notification_addfd_rlimit)
41254164 EXPECT_EQ (ioctl (listener , SECCOMP_IOCTL_NOTIF_ADDFD , & addfd ), -1 );
41264165 EXPECT_EQ (errno , EMFILE );
41274166
4167+ addfd .flags = SECCOMP_ADDFD_FLAG_SEND ;
4168+ EXPECT_EQ (ioctl (listener , SECCOMP_IOCTL_NOTIF_ADDFD , & addfd ), -1 );
4169+ EXPECT_EQ (errno , EMFILE );
4170+
41284171 addfd .newfd = 100 ;
41294172 addfd .flags = SECCOMP_ADDFD_FLAG_SETFD ;
41304173 EXPECT_EQ (ioctl (listener , SECCOMP_IOCTL_NOTIF_ADDFD , & addfd ), -1 );
0 commit comments