1*8ac5aef8SEnji Cooper // Test that ioctl works in capability mode. 2*8ac5aef8SEnji Cooper #include <sys/types.h> 3*8ac5aef8SEnji Cooper #include <sys/stat.h> 4*8ac5aef8SEnji Cooper #include <sys/socket.h> 5*8ac5aef8SEnji Cooper #include <fcntl.h> 6*8ac5aef8SEnji Cooper #include <sys/ioctl.h> 7*8ac5aef8SEnji Cooper 8*8ac5aef8SEnji Cooper #include "capsicum.h" 9*8ac5aef8SEnji Cooper #include "capsicum-test.h" 10*8ac5aef8SEnji Cooper 11*8ac5aef8SEnji Cooper // Ensure that ioctl() works consistently for both regular file descriptors and 12*8ac5aef8SEnji Cooper // capability-wrapped ones. 13*8ac5aef8SEnji Cooper TEST(Ioctl, Basic) { 14*8ac5aef8SEnji Cooper cap_rights_t rights_ioctl; 15*8ac5aef8SEnji Cooper cap_rights_init(&rights_ioctl, CAP_IOCTL); 16*8ac5aef8SEnji Cooper cap_rights_t rights_many; 17*8ac5aef8SEnji Cooper cap_rights_init(&rights_many, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FSTAT, CAP_FSYNC); 18*8ac5aef8SEnji Cooper 19*8ac5aef8SEnji Cooper int fd = open("/etc/passwd", O_RDONLY); 20*8ac5aef8SEnji Cooper EXPECT_OK(fd); 21*8ac5aef8SEnji Cooper int fd_no = dup(fd); 22*8ac5aef8SEnji Cooper EXPECT_OK(fd_no); 23*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(fd, &rights_ioctl)); 24*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(fd_no, &rights_many)); 25*8ac5aef8SEnji Cooper 26*8ac5aef8SEnji Cooper // Check that CAP_IOCTL is required. 27*8ac5aef8SEnji Cooper int bytes; 28*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd, FIONREAD, &bytes)); 29*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(ioctl(fd_no, FIONREAD, &bytes)); 30*8ac5aef8SEnji Cooper 31*8ac5aef8SEnji Cooper int one = 1; 32*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd, FIOCLEX, &one)); 33*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(ioctl(fd_no, FIOCLEX, &one)); 34*8ac5aef8SEnji Cooper 35*8ac5aef8SEnji Cooper close(fd); 36*8ac5aef8SEnji Cooper close(fd_no); 37*8ac5aef8SEnji Cooper } 38*8ac5aef8SEnji Cooper 39*8ac5aef8SEnji Cooper #ifdef HAVE_CAP_IOCTLS_LIMIT 40*8ac5aef8SEnji Cooper TEST(Ioctl, SubRightNormalFD) { 41*8ac5aef8SEnji Cooper int fd = open("/etc/passwd", O_RDONLY); 42*8ac5aef8SEnji Cooper EXPECT_OK(fd); 43*8ac5aef8SEnji Cooper 44*8ac5aef8SEnji Cooper // Restrict the ioctl(2) subrights of a normal FD. 45*8ac5aef8SEnji Cooper cap_ioctl_t ioctl_nread = FIONREAD; 46*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd, &ioctl_nread, 1)); 47*8ac5aef8SEnji Cooper int bytes; 48*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd, FIONREAD, &bytes)); 49*8ac5aef8SEnji Cooper int one = 1; 50*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(ioctl(fd, FIOCLEX, &one)); 51*8ac5aef8SEnji Cooper 52*8ac5aef8SEnji Cooper // Expect to have all primary rights. 53*8ac5aef8SEnji Cooper cap_rights_t rights; 54*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_get(fd, &rights)); 55*8ac5aef8SEnji Cooper cap_rights_t all; 56*8ac5aef8SEnji Cooper CAP_SET_ALL(&all); 57*8ac5aef8SEnji Cooper EXPECT_RIGHTS_EQ(&all, &rights); 58*8ac5aef8SEnji Cooper cap_ioctl_t ioctls[16]; 59*8ac5aef8SEnji Cooper memset(ioctls, 0, sizeof(ioctls)); 60*8ac5aef8SEnji Cooper ssize_t nioctls = cap_ioctls_get(fd, ioctls, 16); 61*8ac5aef8SEnji Cooper EXPECT_OK(nioctls); 62*8ac5aef8SEnji Cooper EXPECT_EQ(1, nioctls); 63*8ac5aef8SEnji Cooper EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]); 64*8ac5aef8SEnji Cooper 65*8ac5aef8SEnji Cooper // Can't widen the subrights. 66*8ac5aef8SEnji Cooper cap_ioctl_t both_ioctls[2] = {FIONREAD, FIOCLEX}; 67*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(cap_ioctls_limit(fd, both_ioctls, 2)); 68*8ac5aef8SEnji Cooper 69*8ac5aef8SEnji Cooper close(fd); 70*8ac5aef8SEnji Cooper } 71*8ac5aef8SEnji Cooper 72*8ac5aef8SEnji Cooper TEST(Ioctl, PreserveSubRights) { 73*8ac5aef8SEnji Cooper int fd = open("/etc/passwd", O_RDONLY); 74*8ac5aef8SEnji Cooper EXPECT_OK(fd); 75*8ac5aef8SEnji Cooper cap_rights_t rights; 76*8ac5aef8SEnji Cooper cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_IOCTL); 77*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(fd, &rights)); 78*8ac5aef8SEnji Cooper cap_ioctl_t ioctl_nread = FIONREAD; 79*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd, &ioctl_nread, 1)); 80*8ac5aef8SEnji Cooper 81*8ac5aef8SEnji Cooper cap_rights_t cur_rights; 82*8ac5aef8SEnji Cooper cap_ioctl_t ioctls[16]; 83*8ac5aef8SEnji Cooper ssize_t nioctls; 84*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_get(fd, &cur_rights)); 85*8ac5aef8SEnji Cooper EXPECT_RIGHTS_EQ(&rights, &cur_rights); 86*8ac5aef8SEnji Cooper nioctls = cap_ioctls_get(fd, ioctls, 16); 87*8ac5aef8SEnji Cooper EXPECT_OK(nioctls); 88*8ac5aef8SEnji Cooper EXPECT_EQ(1, nioctls); 89*8ac5aef8SEnji Cooper EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]); 90*8ac5aef8SEnji Cooper 91*8ac5aef8SEnji Cooper // Limiting the top-level rights leaves the subrights unaffected... 92*8ac5aef8SEnji Cooper cap_rights_clear(&rights, CAP_READ); 93*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(fd, &rights)); 94*8ac5aef8SEnji Cooper nioctls = cap_ioctls_get(fd, ioctls, 16); 95*8ac5aef8SEnji Cooper EXPECT_OK(nioctls); 96*8ac5aef8SEnji Cooper EXPECT_EQ(1, nioctls); 97*8ac5aef8SEnji Cooper EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]); 98*8ac5aef8SEnji Cooper 99*8ac5aef8SEnji Cooper // ... until we remove CAP_IOCTL 100*8ac5aef8SEnji Cooper cap_rights_clear(&rights, CAP_IOCTL); 101*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(fd, &rights)); 102*8ac5aef8SEnji Cooper nioctls = cap_ioctls_get(fd, ioctls, 16); 103*8ac5aef8SEnji Cooper EXPECT_OK(nioctls); 104*8ac5aef8SEnji Cooper EXPECT_EQ(0, nioctls); 105*8ac5aef8SEnji Cooper EXPECT_EQ(-1, cap_ioctls_limit(fd, &ioctl_nread, 1)); 106*8ac5aef8SEnji Cooper 107*8ac5aef8SEnji Cooper close(fd); 108*8ac5aef8SEnji Cooper } 109*8ac5aef8SEnji Cooper 110*8ac5aef8SEnji Cooper TEST(Ioctl, SubRights) { 111*8ac5aef8SEnji Cooper int fd = open("/etc/passwd", O_RDONLY); 112*8ac5aef8SEnji Cooper EXPECT_OK(fd); 113*8ac5aef8SEnji Cooper 114*8ac5aef8SEnji Cooper cap_ioctl_t ioctls[16]; 115*8ac5aef8SEnji Cooper ssize_t nioctls; 116*8ac5aef8SEnji Cooper memset(ioctls, 0, sizeof(ioctls)); 117*8ac5aef8SEnji Cooper nioctls = cap_ioctls_get(fd, ioctls, 16); 118*8ac5aef8SEnji Cooper EXPECT_OK(nioctls); 119*8ac5aef8SEnji Cooper EXPECT_EQ(CAP_IOCTLS_ALL, nioctls); 120*8ac5aef8SEnji Cooper 121*8ac5aef8SEnji Cooper cap_rights_t rights_ioctl; 122*8ac5aef8SEnji Cooper cap_rights_init(&rights_ioctl, CAP_IOCTL); 123*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(fd, &rights_ioctl)); 124*8ac5aef8SEnji Cooper 125*8ac5aef8SEnji Cooper nioctls = cap_ioctls_get(fd, ioctls, 16); 126*8ac5aef8SEnji Cooper EXPECT_OK(nioctls); 127*8ac5aef8SEnji Cooper EXPECT_EQ(CAP_IOCTLS_ALL, nioctls); 128*8ac5aef8SEnji Cooper 129*8ac5aef8SEnji Cooper // Check operations that need CAP_IOCTL with subrights pristine => OK. 130*8ac5aef8SEnji Cooper int bytes; 131*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd, FIONREAD, &bytes)); 132*8ac5aef8SEnji Cooper int one = 1; 133*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd, FIOCLEX, &one)); 134*8ac5aef8SEnji Cooper 135*8ac5aef8SEnji Cooper // Check operations that need CAP_IOCTL with all relevant subrights => OK. 136*8ac5aef8SEnji Cooper cap_ioctl_t both_ioctls[2] = {FIONREAD, FIOCLEX}; 137*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd, both_ioctls, 2)); 138*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd, FIONREAD, &bytes)); 139*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd, FIOCLEX, &one)); 140*8ac5aef8SEnji Cooper 141*8ac5aef8SEnji Cooper 142*8ac5aef8SEnji Cooper // Check what happens if we ask for subrights but don't have the space for them. 143*8ac5aef8SEnji Cooper cap_ioctl_t before = 0xBBBBBBBB; 144*8ac5aef8SEnji Cooper cap_ioctl_t one_ioctl = 0; 145*8ac5aef8SEnji Cooper cap_ioctl_t after = 0xAAAAAAAA; 146*8ac5aef8SEnji Cooper nioctls = cap_ioctls_get(fd, &one_ioctl, 1); 147*8ac5aef8SEnji Cooper EXPECT_EQ(2, nioctls); 148*8ac5aef8SEnji Cooper EXPECT_EQ(0xBBBBBBBB, before); 149*8ac5aef8SEnji Cooper EXPECT_TRUE(one_ioctl == FIONREAD || one_ioctl == FIOCLEX); 150*8ac5aef8SEnji Cooper EXPECT_EQ(0xAAAAAAAA, after); 151*8ac5aef8SEnji Cooper 152*8ac5aef8SEnji Cooper // Check operations that need CAP_IOCTL with particular subrights. 153*8ac5aef8SEnji Cooper int fd_nread = dup(fd); 154*8ac5aef8SEnji Cooper int fd_clex = dup(fd); 155*8ac5aef8SEnji Cooper cap_ioctl_t ioctl_nread = FIONREAD; 156*8ac5aef8SEnji Cooper cap_ioctl_t ioctl_clex = FIOCLEX; 157*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd_nread, &ioctl_nread, 1)); 158*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd_clex, &ioctl_clex, 1)); 159*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd_nread, FIONREAD, &bytes)); 160*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(ioctl(fd_clex, FIONREAD, &bytes)); 161*8ac5aef8SEnji Cooper EXPECT_OK(ioctl(fd_clex, FIOCLEX, &one)); 162*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(ioctl(fd_nread, FIOCLEX, &one)); 163*8ac5aef8SEnji Cooper 164*8ac5aef8SEnji Cooper // Also check we can retrieve the subrights. 165*8ac5aef8SEnji Cooper memset(ioctls, 0, sizeof(ioctls)); 166*8ac5aef8SEnji Cooper nioctls = cap_ioctls_get(fd_nread, ioctls, 16); 167*8ac5aef8SEnji Cooper EXPECT_OK(nioctls); 168*8ac5aef8SEnji Cooper EXPECT_EQ(1, nioctls); 169*8ac5aef8SEnji Cooper EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]); 170*8ac5aef8SEnji Cooper memset(ioctls, 0, sizeof(ioctls)); 171*8ac5aef8SEnji Cooper nioctls = cap_ioctls_get(fd_clex, ioctls, 16); 172*8ac5aef8SEnji Cooper EXPECT_OK(nioctls); 173*8ac5aef8SEnji Cooper EXPECT_EQ(1, nioctls); 174*8ac5aef8SEnji Cooper EXPECT_EQ((cap_ioctl_t)FIOCLEX, ioctls[0]); 175*8ac5aef8SEnji Cooper // And that we can't widen the subrights. 176*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(cap_ioctls_limit(fd_nread, both_ioctls, 2)); 177*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(cap_ioctls_limit(fd_clex, both_ioctls, 2)); 178*8ac5aef8SEnji Cooper close(fd_nread); 179*8ac5aef8SEnji Cooper close(fd_clex); 180*8ac5aef8SEnji Cooper 181*8ac5aef8SEnji Cooper // Check operations that need CAP_IOCTL with no subrights => ENOTCAPABLE. 182*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd, NULL, 0)); 183*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(ioctl(fd, FIONREAD, &bytes)); 184*8ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(ioctl(fd, FIOCLEX, &one)); 185*8ac5aef8SEnji Cooper 186*8ac5aef8SEnji Cooper close(fd); 187*8ac5aef8SEnji Cooper } 188*8ac5aef8SEnji Cooper 189*8ac5aef8SEnji Cooper #ifdef CAP_IOCTLS_LIMIT_MAX 190*8ac5aef8SEnji Cooper TEST(Ioctl, TooManySubRights) { 191*8ac5aef8SEnji Cooper int fd = open("/etc/passwd", O_RDONLY); 192*8ac5aef8SEnji Cooper EXPECT_OK(fd); 193*8ac5aef8SEnji Cooper 194*8ac5aef8SEnji Cooper cap_ioctl_t ioctls[CAP_IOCTLS_LIMIT_MAX + 1]; 195*8ac5aef8SEnji Cooper for (int ii = 0; ii <= CAP_IOCTLS_LIMIT_MAX; ii++) { 196*8ac5aef8SEnji Cooper ioctls[ii] = ii + 1; 197*8ac5aef8SEnji Cooper } 198*8ac5aef8SEnji Cooper 199*8ac5aef8SEnji Cooper cap_rights_t rights_ioctl; 200*8ac5aef8SEnji Cooper cap_rights_init(&rights_ioctl, CAP_IOCTL); 201*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(fd, &rights_ioctl)); 202*8ac5aef8SEnji Cooper 203*8ac5aef8SEnji Cooper // Can only limit to a certain number of ioctls 204*8ac5aef8SEnji Cooper EXPECT_EQ(-1, cap_ioctls_limit(fd, ioctls, CAP_IOCTLS_LIMIT_MAX + 1)); 205*8ac5aef8SEnji Cooper EXPECT_EQ(EINVAL, errno); 206*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd, ioctls, CAP_IOCTLS_LIMIT_MAX)); 207*8ac5aef8SEnji Cooper 208*8ac5aef8SEnji Cooper close(fd); 209*8ac5aef8SEnji Cooper } 210*8ac5aef8SEnji Cooper #else 211*8ac5aef8SEnji Cooper TEST(Ioctl, ManySubRights) { 212*8ac5aef8SEnji Cooper int fd = open("/etc/passwd", O_RDONLY); 213*8ac5aef8SEnji Cooper EXPECT_OK(fd); 214*8ac5aef8SEnji Cooper 215*8ac5aef8SEnji Cooper const int nioctls = 150000; 216*8ac5aef8SEnji Cooper cap_ioctl_t* ioctls = (cap_ioctl_t*)calloc(nioctls, sizeof(cap_ioctl_t)); 217*8ac5aef8SEnji Cooper for (int ii = 0; ii < nioctls; ii++) { 218*8ac5aef8SEnji Cooper ioctls[ii] = ii + 1; 219*8ac5aef8SEnji Cooper } 220*8ac5aef8SEnji Cooper 221*8ac5aef8SEnji Cooper cap_rights_t rights_ioctl; 222*8ac5aef8SEnji Cooper cap_rights_init(&rights_ioctl, CAP_IOCTL); 223*8ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(fd, &rights_ioctl)); 224*8ac5aef8SEnji Cooper 225*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd, ioctls, nioctls)); 226*8ac5aef8SEnji Cooper // Limit to a subset; if this takes a long time then there's an 227*8ac5aef8SEnji Cooper // O(N^2) implementation of the ioctl list comparison. 228*8ac5aef8SEnji Cooper EXPECT_OK(cap_ioctls_limit(fd, ioctls, nioctls - 1)); 229*8ac5aef8SEnji Cooper 230*8ac5aef8SEnji Cooper close(fd); 231*8ac5aef8SEnji Cooper } 232*8ac5aef8SEnji Cooper #endif 233*8ac5aef8SEnji Cooper 234*8ac5aef8SEnji Cooper #endif 235