root/tools/testing/selftests/bpf/prog_tests/sockopt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. load_prog
  2. run_test
  3. test_sockopt

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <test_progs.h>
   3 #include "cgroup_helpers.h"
   4 
   5 static char bpf_log_buf[4096];
   6 static bool verbose;
   7 
   8 enum sockopt_test_error {
   9         OK = 0,
  10         DENY_LOAD,
  11         DENY_ATTACH,
  12         EPERM_GETSOCKOPT,
  13         EFAULT_GETSOCKOPT,
  14         EPERM_SETSOCKOPT,
  15         EFAULT_SETSOCKOPT,
  16 };
  17 
  18 static struct sockopt_test {
  19         const char                      *descr;
  20         const struct bpf_insn           insns[64];
  21         enum bpf_attach_type            attach_type;
  22         enum bpf_attach_type            expected_attach_type;
  23 
  24         int                             set_optname;
  25         int                             set_level;
  26         const char                      set_optval[64];
  27         socklen_t                       set_optlen;
  28 
  29         int                             get_optname;
  30         int                             get_level;
  31         const char                      get_optval[64];
  32         socklen_t                       get_optlen;
  33         socklen_t                       get_optlen_ret;
  34 
  35         enum sockopt_test_error         error;
  36 } tests[] = {
  37 
  38         /* ==================== getsockopt ====================  */
  39 
  40         {
  41                 .descr = "getsockopt: no expected_attach_type",
  42                 .insns = {
  43                         /* return 1 */
  44                         BPF_MOV64_IMM(BPF_REG_0, 1),
  45                         BPF_EXIT_INSN(),
  46 
  47                 },
  48                 .attach_type = BPF_CGROUP_GETSOCKOPT,
  49                 .expected_attach_type = 0,
  50                 .error = DENY_LOAD,
  51         },
  52         {
  53                 .descr = "getsockopt: wrong expected_attach_type",
  54                 .insns = {
  55                         /* return 1 */
  56                         BPF_MOV64_IMM(BPF_REG_0, 1),
  57                         BPF_EXIT_INSN(),
  58 
  59                 },
  60                 .attach_type = BPF_CGROUP_GETSOCKOPT,
  61                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
  62                 .error = DENY_ATTACH,
  63         },
  64         {
  65                 .descr = "getsockopt: bypass bpf hook",
  66                 .insns = {
  67                         /* return 1 */
  68                         BPF_MOV64_IMM(BPF_REG_0, 1),
  69                         BPF_EXIT_INSN(),
  70                 },
  71                 .attach_type = BPF_CGROUP_GETSOCKOPT,
  72                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
  73 
  74                 .get_level = SOL_IP,
  75                 .set_level = SOL_IP,
  76 
  77                 .get_optname = IP_TOS,
  78                 .set_optname = IP_TOS,
  79 
  80                 .set_optval = { 1 << 3 },
  81                 .set_optlen = 1,
  82 
  83                 .get_optval = { 1 << 3 },
  84                 .get_optlen = 1,
  85         },
  86         {
  87                 .descr = "getsockopt: return EPERM from bpf hook",
  88                 .insns = {
  89                         BPF_MOV64_IMM(BPF_REG_0, 0),
  90                         BPF_EXIT_INSN(),
  91                 },
  92                 .attach_type = BPF_CGROUP_GETSOCKOPT,
  93                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
  94 
  95                 .get_level = SOL_IP,
  96                 .get_optname = IP_TOS,
  97 
  98                 .get_optlen = 1,
  99                 .error = EPERM_GETSOCKOPT,
 100         },
 101         {
 102                 .descr = "getsockopt: no optval bounds check, deny loading",
 103                 .insns = {
 104                         /* r6 = ctx->optval */
 105                         BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
 106                                     offsetof(struct bpf_sockopt, optval)),
 107 
 108                         /* ctx->optval[0] = 0x80 */
 109                         BPF_MOV64_IMM(BPF_REG_0, 0x80),
 110                         BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0),
 111 
 112                         /* return 1 */
 113                         BPF_MOV64_IMM(BPF_REG_0, 1),
 114                         BPF_EXIT_INSN(),
 115                 },
 116                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 117                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 118                 .error = DENY_LOAD,
 119         },
 120         {
 121                 .descr = "getsockopt: read ctx->level",
 122                 .insns = {
 123                         /* r6 = ctx->level */
 124                         BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
 125                                     offsetof(struct bpf_sockopt, level)),
 126 
 127                         /* if (ctx->level == 123) { */
 128                         BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
 129                         /* ctx->retval = 0 */
 130                         BPF_MOV64_IMM(BPF_REG_0, 0),
 131                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 132                                     offsetof(struct bpf_sockopt, retval)),
 133                         /* return 1 */
 134                         BPF_MOV64_IMM(BPF_REG_0, 1),
 135                         BPF_JMP_A(1),
 136                         /* } else { */
 137                         /* return 0 */
 138                         BPF_MOV64_IMM(BPF_REG_0, 0),
 139                         /* } */
 140                         BPF_EXIT_INSN(),
 141                 },
 142                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 143                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 144 
 145                 .get_level = 123,
 146 
 147                 .get_optlen = 1,
 148         },
 149         {
 150                 .descr = "getsockopt: deny writing to ctx->level",
 151                 .insns = {
 152                         /* ctx->level = 1 */
 153                         BPF_MOV64_IMM(BPF_REG_0, 1),
 154                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 155                                     offsetof(struct bpf_sockopt, level)),
 156                         BPF_EXIT_INSN(),
 157                 },
 158                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 159                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 160 
 161                 .error = DENY_LOAD,
 162         },
 163         {
 164                 .descr = "getsockopt: read ctx->optname",
 165                 .insns = {
 166                         /* r6 = ctx->optname */
 167                         BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
 168                                     offsetof(struct bpf_sockopt, optname)),
 169 
 170                         /* if (ctx->optname == 123) { */
 171                         BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
 172                         /* ctx->retval = 0 */
 173                         BPF_MOV64_IMM(BPF_REG_0, 0),
 174                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 175                                     offsetof(struct bpf_sockopt, retval)),
 176                         /* return 1 */
 177                         BPF_MOV64_IMM(BPF_REG_0, 1),
 178                         BPF_JMP_A(1),
 179                         /* } else { */
 180                         /* return 0 */
 181                         BPF_MOV64_IMM(BPF_REG_0, 0),
 182                         /* } */
 183                         BPF_EXIT_INSN(),
 184                 },
 185                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 186                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 187 
 188                 .get_optname = 123,
 189 
 190                 .get_optlen = 1,
 191         },
 192         {
 193                 .descr = "getsockopt: read ctx->retval",
 194                 .insns = {
 195                         /* r6 = ctx->retval */
 196                         BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
 197                                     offsetof(struct bpf_sockopt, retval)),
 198 
 199                         /* return 1 */
 200                         BPF_MOV64_IMM(BPF_REG_0, 1),
 201                         BPF_EXIT_INSN(),
 202                 },
 203                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 204                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 205 
 206                 .get_level = SOL_IP,
 207                 .get_optname = IP_TOS,
 208                 .get_optlen = 1,
 209         },
 210         {
 211                 .descr = "getsockopt: deny writing to ctx->optname",
 212                 .insns = {
 213                         /* ctx->optname = 1 */
 214                         BPF_MOV64_IMM(BPF_REG_0, 1),
 215                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 216                                     offsetof(struct bpf_sockopt, optname)),
 217                         BPF_EXIT_INSN(),
 218                 },
 219                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 220                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 221 
 222                 .error = DENY_LOAD,
 223         },
 224         {
 225                 .descr = "getsockopt: read ctx->optlen",
 226                 .insns = {
 227                         /* r6 = ctx->optlen */
 228                         BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
 229                                     offsetof(struct bpf_sockopt, optlen)),
 230 
 231                         /* if (ctx->optlen == 64) { */
 232                         BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
 233                         /* ctx->retval = 0 */
 234                         BPF_MOV64_IMM(BPF_REG_0, 0),
 235                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 236                                     offsetof(struct bpf_sockopt, retval)),
 237                         /* return 1 */
 238                         BPF_MOV64_IMM(BPF_REG_0, 1),
 239                         BPF_JMP_A(1),
 240                         /* } else { */
 241                         /* return 0 */
 242                         BPF_MOV64_IMM(BPF_REG_0, 0),
 243                         /* } */
 244                         BPF_EXIT_INSN(),
 245                 },
 246                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 247                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 248 
 249                 .get_optlen = 64,
 250         },
 251         {
 252                 .descr = "getsockopt: deny bigger ctx->optlen",
 253                 .insns = {
 254                         /* ctx->optlen = 65 */
 255                         BPF_MOV64_IMM(BPF_REG_0, 65),
 256                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 257                                     offsetof(struct bpf_sockopt, optlen)),
 258 
 259                         /* ctx->retval = 0 */
 260                         BPF_MOV64_IMM(BPF_REG_0, 0),
 261                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 262                                     offsetof(struct bpf_sockopt, retval)),
 263 
 264                         /* return 1 */
 265                         BPF_MOV64_IMM(BPF_REG_0, 1),
 266                         BPF_EXIT_INSN(),
 267                 },
 268                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 269                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 270 
 271                 .get_optlen = 64,
 272 
 273                 .error = EFAULT_GETSOCKOPT,
 274         },
 275         {
 276                 .descr = "getsockopt: deny arbitrary ctx->retval",
 277                 .insns = {
 278                         /* ctx->retval = 123 */
 279                         BPF_MOV64_IMM(BPF_REG_0, 123),
 280                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 281                                     offsetof(struct bpf_sockopt, retval)),
 282 
 283                         /* return 1 */
 284                         BPF_MOV64_IMM(BPF_REG_0, 1),
 285                         BPF_EXIT_INSN(),
 286                 },
 287                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 288                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 289 
 290                 .get_optlen = 64,
 291 
 292                 .error = EFAULT_GETSOCKOPT,
 293         },
 294         {
 295                 .descr = "getsockopt: support smaller ctx->optlen",
 296                 .insns = {
 297                         /* ctx->optlen = 32 */
 298                         BPF_MOV64_IMM(BPF_REG_0, 32),
 299                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 300                                     offsetof(struct bpf_sockopt, optlen)),
 301                         /* ctx->retval = 0 */
 302                         BPF_MOV64_IMM(BPF_REG_0, 0),
 303                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 304                                     offsetof(struct bpf_sockopt, retval)),
 305                         /* return 1 */
 306                         BPF_MOV64_IMM(BPF_REG_0, 1),
 307                         BPF_EXIT_INSN(),
 308                 },
 309                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 310                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 311 
 312                 .get_optlen = 64,
 313                 .get_optlen_ret = 32,
 314         },
 315         {
 316                 .descr = "getsockopt: deny writing to ctx->optval",
 317                 .insns = {
 318                         /* ctx->optval = 1 */
 319                         BPF_MOV64_IMM(BPF_REG_0, 1),
 320                         BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
 321                                     offsetof(struct bpf_sockopt, optval)),
 322                         BPF_EXIT_INSN(),
 323                 },
 324                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 325                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 326 
 327                 .error = DENY_LOAD,
 328         },
 329         {
 330                 .descr = "getsockopt: deny writing to ctx->optval_end",
 331                 .insns = {
 332                         /* ctx->optval_end = 1 */
 333                         BPF_MOV64_IMM(BPF_REG_0, 1),
 334                         BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
 335                                     offsetof(struct bpf_sockopt, optval_end)),
 336                         BPF_EXIT_INSN(),
 337                 },
 338                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 339                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 340 
 341                 .error = DENY_LOAD,
 342         },
 343         {
 344                 .descr = "getsockopt: rewrite value",
 345                 .insns = {
 346                         /* r6 = ctx->optval */
 347                         BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
 348                                     offsetof(struct bpf_sockopt, optval)),
 349                         /* r2 = ctx->optval */
 350                         BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
 351                         /* r6 = ctx->optval + 1 */
 352                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
 353 
 354                         /* r7 = ctx->optval_end */
 355                         BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
 356                                     offsetof(struct bpf_sockopt, optval_end)),
 357 
 358                         /* if (ctx->optval + 1 <= ctx->optval_end) { */
 359                         BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
 360                         /* ctx->optval[0] = 0xF0 */
 361                         BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0),
 362                         /* } */
 363 
 364                         /* ctx->retval = 0 */
 365                         BPF_MOV64_IMM(BPF_REG_0, 0),
 366                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 367                                     offsetof(struct bpf_sockopt, retval)),
 368 
 369                         /* return 1*/
 370                         BPF_MOV64_IMM(BPF_REG_0, 1),
 371                         BPF_EXIT_INSN(),
 372                 },
 373                 .attach_type = BPF_CGROUP_GETSOCKOPT,
 374                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 375 
 376                 .get_level = SOL_IP,
 377                 .get_optname = IP_TOS,
 378 
 379                 .get_optval = { 0xF0 },
 380                 .get_optlen = 1,
 381         },
 382 
 383         /* ==================== setsockopt ====================  */
 384 
 385         {
 386                 .descr = "setsockopt: no expected_attach_type",
 387                 .insns = {
 388                         /* return 1 */
 389                         BPF_MOV64_IMM(BPF_REG_0, 1),
 390                         BPF_EXIT_INSN(),
 391 
 392                 },
 393                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 394                 .expected_attach_type = 0,
 395                 .error = DENY_LOAD,
 396         },
 397         {
 398                 .descr = "setsockopt: wrong expected_attach_type",
 399                 .insns = {
 400                         /* return 1 */
 401                         BPF_MOV64_IMM(BPF_REG_0, 1),
 402                         BPF_EXIT_INSN(),
 403 
 404                 },
 405                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 406                 .expected_attach_type = BPF_CGROUP_GETSOCKOPT,
 407                 .error = DENY_ATTACH,
 408         },
 409         {
 410                 .descr = "setsockopt: bypass bpf hook",
 411                 .insns = {
 412                         /* return 1 */
 413                         BPF_MOV64_IMM(BPF_REG_0, 1),
 414                         BPF_EXIT_INSN(),
 415                 },
 416                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 417                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 418 
 419                 .get_level = SOL_IP,
 420                 .set_level = SOL_IP,
 421 
 422                 .get_optname = IP_TOS,
 423                 .set_optname = IP_TOS,
 424 
 425                 .set_optval = { 1 << 3 },
 426                 .set_optlen = 1,
 427 
 428                 .get_optval = { 1 << 3 },
 429                 .get_optlen = 1,
 430         },
 431         {
 432                 .descr = "setsockopt: return EPERM from bpf hook",
 433                 .insns = {
 434                         /* return 0 */
 435                         BPF_MOV64_IMM(BPF_REG_0, 0),
 436                         BPF_EXIT_INSN(),
 437                 },
 438                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 439                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 440 
 441                 .set_level = SOL_IP,
 442                 .set_optname = IP_TOS,
 443 
 444                 .set_optlen = 1,
 445                 .error = EPERM_SETSOCKOPT,
 446         },
 447         {
 448                 .descr = "setsockopt: no optval bounds check, deny loading",
 449                 .insns = {
 450                         /* r6 = ctx->optval */
 451                         BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
 452                                     offsetof(struct bpf_sockopt, optval)),
 453 
 454                         /* r0 = ctx->optval[0] */
 455                         BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0),
 456 
 457                         /* return 1 */
 458                         BPF_MOV64_IMM(BPF_REG_0, 1),
 459                         BPF_EXIT_INSN(),
 460                 },
 461                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 462                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 463                 .error = DENY_LOAD,
 464         },
 465         {
 466                 .descr = "setsockopt: read ctx->level",
 467                 .insns = {
 468                         /* r6 = ctx->level */
 469                         BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
 470                                     offsetof(struct bpf_sockopt, level)),
 471 
 472                         /* if (ctx->level == 123) { */
 473                         BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
 474                         /* ctx->optlen = -1 */
 475                         BPF_MOV64_IMM(BPF_REG_0, -1),
 476                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 477                                     offsetof(struct bpf_sockopt, optlen)),
 478                         /* return 1 */
 479                         BPF_MOV64_IMM(BPF_REG_0, 1),
 480                         BPF_JMP_A(1),
 481                         /* } else { */
 482                         /* return 0 */
 483                         BPF_MOV64_IMM(BPF_REG_0, 0),
 484                         /* } */
 485                         BPF_EXIT_INSN(),
 486                 },
 487                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 488                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 489 
 490                 .set_level = 123,
 491 
 492                 .set_optlen = 1,
 493         },
 494         {
 495                 .descr = "setsockopt: allow changing ctx->level",
 496                 .insns = {
 497                         /* ctx->level = SOL_IP */
 498                         BPF_MOV64_IMM(BPF_REG_0, SOL_IP),
 499                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 500                                     offsetof(struct bpf_sockopt, level)),
 501                         /* return 1 */
 502                         BPF_MOV64_IMM(BPF_REG_0, 1),
 503                         BPF_EXIT_INSN(),
 504                 },
 505                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 506                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 507 
 508                 .get_level = SOL_IP,
 509                 .set_level = 234, /* should be rewritten to SOL_IP */
 510 
 511                 .get_optname = IP_TOS,
 512                 .set_optname = IP_TOS,
 513 
 514                 .set_optval = { 1 << 3 },
 515                 .set_optlen = 1,
 516                 .get_optval = { 1 << 3 },
 517                 .get_optlen = 1,
 518         },
 519         {
 520                 .descr = "setsockopt: read ctx->optname",
 521                 .insns = {
 522                         /* r6 = ctx->optname */
 523                         BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
 524                                     offsetof(struct bpf_sockopt, optname)),
 525 
 526                         /* if (ctx->optname == 123) { */
 527                         BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4),
 528                         /* ctx->optlen = -1 */
 529                         BPF_MOV64_IMM(BPF_REG_0, -1),
 530                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 531                                     offsetof(struct bpf_sockopt, optlen)),
 532                         /* return 1 */
 533                         BPF_MOV64_IMM(BPF_REG_0, 1),
 534                         BPF_JMP_A(1),
 535                         /* } else { */
 536                         /* return 0 */
 537                         BPF_MOV64_IMM(BPF_REG_0, 0),
 538                         /* } */
 539                         BPF_EXIT_INSN(),
 540                 },
 541                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 542                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 543 
 544                 .set_optname = 123,
 545 
 546                 .set_optlen = 1,
 547         },
 548         {
 549                 .descr = "setsockopt: allow changing ctx->optname",
 550                 .insns = {
 551                         /* ctx->optname = IP_TOS */
 552                         BPF_MOV64_IMM(BPF_REG_0, IP_TOS),
 553                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 554                                     offsetof(struct bpf_sockopt, optname)),
 555                         /* return 1 */
 556                         BPF_MOV64_IMM(BPF_REG_0, 1),
 557                         BPF_EXIT_INSN(),
 558                 },
 559                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 560                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 561 
 562                 .get_level = SOL_IP,
 563                 .set_level = SOL_IP,
 564 
 565                 .get_optname = IP_TOS,
 566                 .set_optname = 456, /* should be rewritten to IP_TOS */
 567 
 568                 .set_optval = { 1 << 3 },
 569                 .set_optlen = 1,
 570                 .get_optval = { 1 << 3 },
 571                 .get_optlen = 1,
 572         },
 573         {
 574                 .descr = "setsockopt: read ctx->optlen",
 575                 .insns = {
 576                         /* r6 = ctx->optlen */
 577                         BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
 578                                     offsetof(struct bpf_sockopt, optlen)),
 579 
 580                         /* if (ctx->optlen == 64) { */
 581                         BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4),
 582                         /* ctx->optlen = -1 */
 583                         BPF_MOV64_IMM(BPF_REG_0, -1),
 584                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 585                                     offsetof(struct bpf_sockopt, optlen)),
 586                         /* return 1 */
 587                         BPF_MOV64_IMM(BPF_REG_0, 1),
 588                         BPF_JMP_A(1),
 589                         /* } else { */
 590                         /* return 0 */
 591                         BPF_MOV64_IMM(BPF_REG_0, 0),
 592                         /* } */
 593                         BPF_EXIT_INSN(),
 594                 },
 595                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 596                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 597 
 598                 .set_optlen = 64,
 599         },
 600         {
 601                 .descr = "setsockopt: ctx->optlen == -1 is ok",
 602                 .insns = {
 603                         /* ctx->optlen = -1 */
 604                         BPF_MOV64_IMM(BPF_REG_0, -1),
 605                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 606                                     offsetof(struct bpf_sockopt, optlen)),
 607                         /* return 1 */
 608                         BPF_MOV64_IMM(BPF_REG_0, 1),
 609                         BPF_EXIT_INSN(),
 610                 },
 611                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 612                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 613 
 614                 .set_optlen = 64,
 615         },
 616         {
 617                 .descr = "setsockopt: deny ctx->optlen < 0 (except -1)",
 618                 .insns = {
 619                         /* ctx->optlen = -2 */
 620                         BPF_MOV64_IMM(BPF_REG_0, -2),
 621                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 622                                     offsetof(struct bpf_sockopt, optlen)),
 623                         /* return 1 */
 624                         BPF_MOV64_IMM(BPF_REG_0, 1),
 625                         BPF_EXIT_INSN(),
 626                 },
 627                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 628                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 629 
 630                 .set_optlen = 4,
 631 
 632                 .error = EFAULT_SETSOCKOPT,
 633         },
 634         {
 635                 .descr = "setsockopt: deny ctx->optlen > input optlen",
 636                 .insns = {
 637                         /* ctx->optlen = 65 */
 638                         BPF_MOV64_IMM(BPF_REG_0, 65),
 639                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 640                                     offsetof(struct bpf_sockopt, optlen)),
 641                         BPF_MOV64_IMM(BPF_REG_0, 1),
 642                         BPF_EXIT_INSN(),
 643                 },
 644                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 645                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 646 
 647                 .set_optlen = 64,
 648 
 649                 .error = EFAULT_SETSOCKOPT,
 650         },
 651         {
 652                 .descr = "setsockopt: allow changing ctx->optlen within bounds",
 653                 .insns = {
 654                         /* r6 = ctx->optval */
 655                         BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
 656                                     offsetof(struct bpf_sockopt, optval)),
 657                         /* r2 = ctx->optval */
 658                         BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
 659                         /* r6 = ctx->optval + 1 */
 660                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1),
 661 
 662                         /* r7 = ctx->optval_end */
 663                         BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1,
 664                                     offsetof(struct bpf_sockopt, optval_end)),
 665 
 666                         /* if (ctx->optval + 1 <= ctx->optval_end) { */
 667                         BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1),
 668                         /* ctx->optval[0] = 1 << 3 */
 669                         BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 1 << 3),
 670                         /* } */
 671 
 672                         /* ctx->optlen = 1 */
 673                         BPF_MOV64_IMM(BPF_REG_0, 1),
 674                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 675                                     offsetof(struct bpf_sockopt, optlen)),
 676 
 677                         /* return 1*/
 678                         BPF_MOV64_IMM(BPF_REG_0, 1),
 679                         BPF_EXIT_INSN(),
 680                 },
 681                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 682                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 683 
 684                 .get_level = SOL_IP,
 685                 .set_level = SOL_IP,
 686 
 687                 .get_optname = IP_TOS,
 688                 .set_optname = IP_TOS,
 689 
 690                 .set_optval = { 1, 1, 1, 1 },
 691                 .set_optlen = 4,
 692                 .get_optval = { 1 << 3 },
 693                 .get_optlen = 1,
 694         },
 695         {
 696                 .descr = "setsockopt: deny write ctx->retval",
 697                 .insns = {
 698                         /* ctx->retval = 0 */
 699                         BPF_MOV64_IMM(BPF_REG_0, 0),
 700                         BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
 701                                     offsetof(struct bpf_sockopt, retval)),
 702 
 703                         /* return 1 */
 704                         BPF_MOV64_IMM(BPF_REG_0, 1),
 705                         BPF_EXIT_INSN(),
 706                 },
 707                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 708                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 709 
 710                 .error = DENY_LOAD,
 711         },
 712         {
 713                 .descr = "setsockopt: deny read ctx->retval",
 714                 .insns = {
 715                         /* r6 = ctx->retval */
 716                         BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
 717                                     offsetof(struct bpf_sockopt, retval)),
 718 
 719                         /* return 1 */
 720                         BPF_MOV64_IMM(BPF_REG_0, 1),
 721                         BPF_EXIT_INSN(),
 722                 },
 723                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 724                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 725 
 726                 .error = DENY_LOAD,
 727         },
 728         {
 729                 .descr = "setsockopt: deny writing to ctx->optval",
 730                 .insns = {
 731                         /* ctx->optval = 1 */
 732                         BPF_MOV64_IMM(BPF_REG_0, 1),
 733                         BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
 734                                     offsetof(struct bpf_sockopt, optval)),
 735                         BPF_EXIT_INSN(),
 736                 },
 737                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 738                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 739 
 740                 .error = DENY_LOAD,
 741         },
 742         {
 743                 .descr = "setsockopt: deny writing to ctx->optval_end",
 744                 .insns = {
 745                         /* ctx->optval_end = 1 */
 746                         BPF_MOV64_IMM(BPF_REG_0, 1),
 747                         BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
 748                                     offsetof(struct bpf_sockopt, optval_end)),
 749                         BPF_EXIT_INSN(),
 750                 },
 751                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 752                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 753 
 754                 .error = DENY_LOAD,
 755         },
 756         {
 757                 .descr = "setsockopt: allow IP_TOS <= 128",
 758                 .insns = {
 759                         /* r6 = ctx->optval */
 760                         BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
 761                                     offsetof(struct bpf_sockopt, optval)),
 762                         /* r7 = ctx->optval + 1 */
 763                         BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
 764                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
 765 
 766                         /* r8 = ctx->optval_end */
 767                         BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
 768                                     offsetof(struct bpf_sockopt, optval_end)),
 769 
 770                         /* if (ctx->optval + 1 <= ctx->optval_end) { */
 771                         BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
 772 
 773                         /* r9 = ctx->optval[0] */
 774                         BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
 775 
 776                         /* if (ctx->optval[0] < 128) */
 777                         BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
 778                         BPF_MOV64_IMM(BPF_REG_0, 1),
 779                         BPF_JMP_A(1),
 780                         /* } */
 781 
 782                         /* } else { */
 783                         BPF_MOV64_IMM(BPF_REG_0, 0),
 784                         /* } */
 785 
 786                         BPF_EXIT_INSN(),
 787                 },
 788                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 789                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 790 
 791                 .get_level = SOL_IP,
 792                 .set_level = SOL_IP,
 793 
 794                 .get_optname = IP_TOS,
 795                 .set_optname = IP_TOS,
 796 
 797                 .set_optval = { 0x80 },
 798                 .set_optlen = 1,
 799                 .get_optval = { 0x80 },
 800                 .get_optlen = 1,
 801         },
 802         {
 803                 .descr = "setsockopt: deny IP_TOS > 128",
 804                 .insns = {
 805                         /* r6 = ctx->optval */
 806                         BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1,
 807                                     offsetof(struct bpf_sockopt, optval)),
 808                         /* r7 = ctx->optval + 1 */
 809                         BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
 810                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
 811 
 812                         /* r8 = ctx->optval_end */
 813                         BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1,
 814                                     offsetof(struct bpf_sockopt, optval_end)),
 815 
 816                         /* if (ctx->optval + 1 <= ctx->optval_end) { */
 817                         BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4),
 818 
 819                         /* r9 = ctx->optval[0] */
 820                         BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0),
 821 
 822                         /* if (ctx->optval[0] < 128) */
 823                         BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2),
 824                         BPF_MOV64_IMM(BPF_REG_0, 1),
 825                         BPF_JMP_A(1),
 826                         /* } */
 827 
 828                         /* } else { */
 829                         BPF_MOV64_IMM(BPF_REG_0, 0),
 830                         /* } */
 831 
 832                         BPF_EXIT_INSN(),
 833                 },
 834                 .attach_type = BPF_CGROUP_SETSOCKOPT,
 835                 .expected_attach_type = BPF_CGROUP_SETSOCKOPT,
 836 
 837                 .get_level = SOL_IP,
 838                 .set_level = SOL_IP,
 839 
 840                 .get_optname = IP_TOS,
 841                 .set_optname = IP_TOS,
 842 
 843                 .set_optval = { 0x81 },
 844                 .set_optlen = 1,
 845                 .get_optval = { 0x00 },
 846                 .get_optlen = 1,
 847 
 848                 .error = EPERM_SETSOCKOPT,
 849         },
 850 };
 851 
 852 static int load_prog(const struct bpf_insn *insns,
 853                      enum bpf_attach_type expected_attach_type)
 854 {
 855         struct bpf_load_program_attr attr = {
 856                 .prog_type = BPF_PROG_TYPE_CGROUP_SOCKOPT,
 857                 .expected_attach_type = expected_attach_type,
 858                 .insns = insns,
 859                 .license = "GPL",
 860                 .log_level = 2,
 861         };
 862         int fd;
 863 
 864         for (;
 865              insns[attr.insns_cnt].code != (BPF_JMP | BPF_EXIT);
 866              attr.insns_cnt++) {
 867         }
 868         attr.insns_cnt++;
 869 
 870         fd = bpf_load_program_xattr(&attr, bpf_log_buf, sizeof(bpf_log_buf));
 871         if (verbose && fd < 0)
 872                 fprintf(stderr, "%s\n", bpf_log_buf);
 873 
 874         return fd;
 875 }
 876 
 877 static int run_test(int cgroup_fd, struct sockopt_test *test)
 878 {
 879         int sock_fd, err, prog_fd;
 880         void *optval = NULL;
 881         int ret = 0;
 882 
 883         prog_fd = load_prog(test->insns, test->expected_attach_type);
 884         if (prog_fd < 0) {
 885                 if (test->error == DENY_LOAD)
 886                         return 0;
 887 
 888                 log_err("Failed to load BPF program");
 889                 return -1;
 890         }
 891 
 892         err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
 893         if (err < 0) {
 894                 if (test->error == DENY_ATTACH)
 895                         goto close_prog_fd;
 896 
 897                 log_err("Failed to attach BPF program");
 898                 ret = -1;
 899                 goto close_prog_fd;
 900         }
 901 
 902         sock_fd = socket(AF_INET, SOCK_STREAM, 0);
 903         if (sock_fd < 0) {
 904                 log_err("Failed to create AF_INET socket");
 905                 ret = -1;
 906                 goto detach_prog;
 907         }
 908 
 909         if (test->set_optlen) {
 910                 err = setsockopt(sock_fd, test->set_level, test->set_optname,
 911                                  test->set_optval, test->set_optlen);
 912                 if (err) {
 913                         if (errno == EPERM && test->error == EPERM_SETSOCKOPT)
 914                                 goto close_sock_fd;
 915                         if (errno == EFAULT && test->error == EFAULT_SETSOCKOPT)
 916                                 goto free_optval;
 917 
 918                         log_err("Failed to call setsockopt");
 919                         ret = -1;
 920                         goto close_sock_fd;
 921                 }
 922         }
 923 
 924         if (test->get_optlen) {
 925                 optval = malloc(test->get_optlen);
 926                 socklen_t optlen = test->get_optlen;
 927                 socklen_t expected_get_optlen = test->get_optlen_ret ?:
 928                         test->get_optlen;
 929 
 930                 err = getsockopt(sock_fd, test->get_level, test->get_optname,
 931                                  optval, &optlen);
 932                 if (err) {
 933                         if (errno == EPERM && test->error == EPERM_GETSOCKOPT)
 934                                 goto free_optval;
 935                         if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT)
 936                                 goto free_optval;
 937 
 938                         log_err("Failed to call getsockopt");
 939                         ret = -1;
 940                         goto free_optval;
 941                 }
 942 
 943                 if (optlen != expected_get_optlen) {
 944                         errno = 0;
 945                         log_err("getsockopt returned unexpected optlen");
 946                         ret = -1;
 947                         goto free_optval;
 948                 }
 949 
 950                 if (memcmp(optval, test->get_optval, optlen) != 0) {
 951                         errno = 0;
 952                         log_err("getsockopt returned unexpected optval");
 953                         ret = -1;
 954                         goto free_optval;
 955                 }
 956         }
 957 
 958         ret = test->error != OK;
 959 
 960 free_optval:
 961         free(optval);
 962 close_sock_fd:
 963         close(sock_fd);
 964 detach_prog:
 965         bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);
 966 close_prog_fd:
 967         close(prog_fd);
 968         return ret;
 969 }
 970 
 971 void test_sockopt(void)
 972 {
 973         int cgroup_fd, i;
 974 
 975         cgroup_fd = test__join_cgroup("/sockopt");
 976         if (CHECK_FAIL(cgroup_fd < 0))
 977                 return;
 978 
 979         for (i = 0; i < ARRAY_SIZE(tests); i++) {
 980                 test__start_subtest(tests[i].descr);
 981                 CHECK_FAIL(run_test(cgroup_fd, &tests[i]));
 982         }
 983 
 984         close(cgroup_fd);
 985 }

/* [<][>][^][v][top][bottom][index][help] */