aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-03-03 09:13:14 +0100
committerShuah Khan <skhan@linuxfoundation.org>2020-05-12 16:12:05 -0600
commit4e546af4f47359445b056c04afdcf5d94759970b (patch)
treecd2a16f7f219704da37e7d679b0d629265ed789b
parent7c8830468f69e03460461c728e52e2c0ff7bb050 (diff)
downloadlinux-arts-4e546af4f47359445b056c04afdcf5d94759970b.tar.gz
linux: add 270 new local repros
Linux reproducers updates from https://github.com/dvyukov/syzkaller-repros Signed-off-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
-rw-r--r--syzkaller-repros/linux/0139a1a5c800cb341ec87d5b6f92ee2a6e505b16.c1609
-rw-r--r--syzkaller-repros/linux/01e50119f4515ff34aca0aff7b80c67196cb5c43.c117
-rw-r--r--syzkaller-repros/linux/03ee30ae11dfd0ddd062af26566c34a8c853698d.c824
-rw-r--r--syzkaller-repros/linux/0401d67c3c0ebbc0a5dbe2167c81376013a31fe4.c294
-rw-r--r--syzkaller-repros/linux/04169338416ff83f7e44c503d9cc93b31c152876.c933
-rw-r--r--syzkaller-repros/linux/048b731781ec88911e03f32b90d91298f040263d.c132
-rw-r--r--syzkaller-repros/linux/04969b1fecdf47ff3849f7fce737fd1ef12b8e4f.c176
-rw-r--r--syzkaller-repros/linux/05505cdef9d15919d3ef0128391540db21272c98.c386
-rw-r--r--syzkaller-repros/linux/063f4f68ef32f5cae06ea84e5fb8d58f2dacab2a.c795
-rw-r--r--syzkaller-repros/linux/07804ed067fcaa4c8967003831699a24e9b634ed.c736
-rw-r--r--syzkaller-repros/linux/0882292577b73fb3a92d45780882a121aa896b83.c317
-rw-r--r--syzkaller-repros/linux/08cce7d51dda77c5900eaedcc3a6acf2f5ad0d3e.c280
-rw-r--r--syzkaller-repros/linux/08e23caab6df4fcf8d6e276eeb4e76b2593478f4.c806
-rw-r--r--syzkaller-repros/linux/0931801760a41b10cdc222d906b87096dfbc699b.c20
-rw-r--r--syzkaller-repros/linux/09a650f7fd6360cfe594f52776cd08e4dea82d6f.c337
-rw-r--r--syzkaller-repros/linux/09e1ccbb75f46c836bdb470380be658050e66942.c403
-rw-r--r--syzkaller-repros/linux/0ab3f49f61f5706bf7883fa10ec9961175f74906.c100
-rw-r--r--syzkaller-repros/linux/0bf321e31faa1d3d4b7c3c8930bc317288d05378.c437
-rw-r--r--syzkaller-repros/linux/0c641fb581d08c1ef69b061b6517c41c180e99d1.c311
-rw-r--r--syzkaller-repros/linux/0d68c5a10991af67c5857fb25a9d33a5f75c69c5.c95
-rw-r--r--syzkaller-repros/linux/0ecb8544c47bb7d668a1951ff5ff4c38c5a32f24.c1203
-rw-r--r--syzkaller-repros/linux/0f798bd6908a49a54cb972b2b92241e5783c6421.c454
-rw-r--r--syzkaller-repros/linux/0fac2c3f760499a1802232af55857850a18713c0.c400
-rw-r--r--syzkaller-repros/linux/10681a527a04da4b77753f36780b87143714d47d.c226
-rw-r--r--syzkaller-repros/linux/107f9ebfce2c1a2ab0331b58ca2f8608b25436c2.c544
-rw-r--r--syzkaller-repros/linux/10857c3f8515a6269522e043228547504abd6455.c341
-rw-r--r--syzkaller-repros/linux/10885c48e038cebd26bcf4ae0c0daa0c6b0607a9.c711
-rw-r--r--syzkaller-repros/linux/1252759d5b2a86c155d9c9d806902955d4edddca.c2024
-rw-r--r--syzkaller-repros/linux/13c53700ac03326096676d67fb7627427bef4972.c460
-rw-r--r--syzkaller-repros/linux/13d6115680ddcb83172032bfa474b252fd00924c.c433
-rw-r--r--syzkaller-repros/linux/1685ca842eda44456e1b2dc3d7136b603f6faa95.c460
-rw-r--r--syzkaller-repros/linux/1765579448a7235f40e5107c35e958fe83e266aa.c176
-rw-r--r--syzkaller-repros/linux/18620d1d7244eb6eb5faef1960308b81f7946ef6.c1405
-rw-r--r--syzkaller-repros/linux/191a661bce16b8880ce500d058c7c7e69fbc8056.c378
-rw-r--r--syzkaller-repros/linux/1a278e3f57cffaa7e62c84a6b0753070a836fe0a.c267
-rw-r--r--syzkaller-repros/linux/1a30aa6e8b48f0a37a2f70f1872e4c81f8b6c4be.c655
-rw-r--r--syzkaller-repros/linux/1aa144a8177fc4c9a38171053370722822172fc9.c2306
-rw-r--r--syzkaller-repros/linux/1b03ffc6e5ce26465bd3c655c7d209c0d51d6aed.c187
-rw-r--r--syzkaller-repros/linux/1b726c0f177e6d976c900f81cf6248473a582459.c579
-rw-r--r--syzkaller-repros/linux/1c457b98011e518f9c572b37d18afff2576b9318.c426
-rw-r--r--syzkaller-repros/linux/1cac1604db07e1f41dc6c9e55489cf2eb5e06840.c218
-rw-r--r--syzkaller-repros/linux/1e212c963d94ea545321e73abef1fda38bfea8dc.c65
-rw-r--r--syzkaller-repros/linux/21e6c5672c9cc31982e846c14c10ec3f6be48546.c818
-rw-r--r--syzkaller-repros/linux/222516e6278a2c349a7e3b662c1a31831f5c85e8.c284
-rw-r--r--syzkaller-repros/linux/2294af0e015d1884b11f0d613be6c3d5585b0f2f.c933
-rw-r--r--syzkaller-repros/linux/22ecdb4eef6e9b264b7a96d8e7ae1cde81d7958c.c355
-rw-r--r--syzkaller-repros/linux/24d6c3a58caeec00e7eb0194ec12b2ecc7099754.c490
-rw-r--r--syzkaller-repros/linux/28fe34b65b6b1224d5f9f1abbc49011dc44f1487.c846
-rw-r--r--syzkaller-repros/linux/290dd60a3f01510810de93fb9825a761a4b99391.c847
-rw-r--r--syzkaller-repros/linux/29fbc1ae06c54940ceeab87c4debcc81108829f4.c1921
-rw-r--r--syzkaller-repros/linux/2a8db7b9aa28c21f3b500e5781edcfd30a70dc4f.c369
-rw-r--r--syzkaller-repros/linux/2af2eeb89a213fc15d0c8d7e31f5dc26f885d62c.c160
-rw-r--r--syzkaller-repros/linux/2b62c2c92d8097048ae927f455695678667b4d28.c754
-rw-r--r--syzkaller-repros/linux/2c02304bfffcd639c6a840b566f6083aed4191e1.c1373
-rw-r--r--syzkaller-repros/linux/2ccb2784ac25def3b08e246ef3a10e1b6e4eb3e3.c1019
-rw-r--r--syzkaller-repros/linux/2d3cae8f6da6f9748ccaece51c90ef808dc02c1e.c344
-rw-r--r--syzkaller-repros/linux/2d970fcf71d6825019b2cb7dd665f4cb4e900ca6.c269
-rw-r--r--syzkaller-repros/linux/2ef9a3fd765fc87a95d0b4a915eb748136d87485.c431
-rw-r--r--syzkaller-repros/linux/2f1a54e3b103141be11150b4dc1d6ee81774a8d5.c156
-rw-r--r--syzkaller-repros/linux/2fdd0aa0525cd6170e6b470d3f4beebcc3c2e063.c280
-rw-r--r--syzkaller-repros/linux/315c108e5692fe6f8a6228e0538dba71bf92583f.c289
-rw-r--r--syzkaller-repros/linux/317ef02b0d5cbd19d445294fed91453c7f970fc3.c299
-rw-r--r--syzkaller-repros/linux/322adf827c43760c788a245ff0e49c8dffd9de9e.c280
-rw-r--r--syzkaller-repros/linux/3452dae8974e3ffaa70ac20870ffda7a786abc12.c226
-rw-r--r--syzkaller-repros/linux/35e19667650e0565c7f9d20e8e9306f919f5ea09.c331
-rw-r--r--syzkaller-repros/linux/3652334fad941714f23fe6bac16b2020baf36296.c589
-rw-r--r--syzkaller-repros/linux/3742e99590e09f89d6f92929fafc9cdad91139f4.c294
-rw-r--r--syzkaller-repros/linux/38274ed551786328c3f7cc4ea683ac544e58696f.c655
-rw-r--r--syzkaller-repros/linux/392a25327e23d5fb6eacf4092fced4405ca198cc.c65
-rw-r--r--syzkaller-repros/linux/3abf33c7e6568401c02c9e3a0abad08faf29c273.c781
-rw-r--r--syzkaller-repros/linux/3c5c8d4347630379dcc10e3d438a1e2f147dcabc.c636
-rw-r--r--syzkaller-repros/linux/3c6d2a9de226763e8c607f53d500aab01b639f2e.c2063
-rw-r--r--syzkaller-repros/linux/3d08e189dea3e9ebfeb32a6c4a1447ad83441556.c875
-rw-r--r--syzkaller-repros/linux/3d6afd8470840e9145db28cc425fea4238c34d14.c316
-rw-r--r--syzkaller-repros/linux/3fc16c8757592a555c9b2faa8757f60d2bdcaacc.c132
-rw-r--r--syzkaller-repros/linux/3ff0b1f7b903343c85ebcd159a6aa4f7916fd7ea.c1475
-rw-r--r--syzkaller-repros/linux/414fc48eb66fb163fb987719fa8c26bb286bef1c.c205
-rw-r--r--syzkaller-repros/linux/41ef72eead121f7189d1cbd590622f386a40e2b3.c695
-rw-r--r--syzkaller-repros/linux/424f2cad4cbb77db7834a34e22b06b0a5e02414e.c723
-rw-r--r--syzkaller-repros/linux/439c37d288d4f26a33a6c7e5c57a97791453a447.c102
-rw-r--r--syzkaller-repros/linux/445ad4be0c26e28632b61b00cb4eb31ccd6de6a7.c1040
-rw-r--r--syzkaller-repros/linux/44793a1c21e8a3df44df46ddf00d44ea0328c0c1.c435
-rw-r--r--syzkaller-repros/linux/466d10a4af6d0a7a4eec73bfba056d0002bd6711.c730
-rw-r--r--syzkaller-repros/linux/46987d0994ee4a9af198f5db904b984f9b2c16b9.c250
-rw-r--r--syzkaller-repros/linux/47327accbf258a249ad43a34e8c15524c4c59d34.c347
-rw-r--r--syzkaller-repros/linux/492d0d91ed2a9cb9ff43f6aace7a2b99a10e6f3f.c578
-rw-r--r--syzkaller-repros/linux/4aa455208960a0581de4d07827f871282e55c78b.c384
-rw-r--r--syzkaller-repros/linux/4ca99bb8684e79c0a748413b46e4a476f35946f3.c400
-rw-r--r--syzkaller-repros/linux/4cb6961fc8d91579e9c254fc74dbee8de06b2b43.c423
-rw-r--r--syzkaller-repros/linux/4e5cba057fd1e1d7a473942ce22d1981be8a2e68.c376
-rw-r--r--syzkaller-repros/linux/4e8f8f42cd1d0965d32183f1805a2c7966e2419b.c390
-rw-r--r--syzkaller-repros/linux/4f9d538745b5c309ed92a48a40bd62b3a80bfe31.c317
-rw-r--r--syzkaller-repros/linux/5286578726824217cc57e8b812bccf039c3ea341.c136
-rw-r--r--syzkaller-repros/linux/53c79be6b6f985867ecf07544b1b962c401cdffe.c294
-rw-r--r--syzkaller-repros/linux/558c547dbb65dc7e36a85d1c8bce3a9f2097c69e.c609
-rw-r--r--syzkaller-repros/linux/55d85e550e13f4a5e3bbe6ca60b6d4c7c448b113.c234
-rw-r--r--syzkaller-repros/linux/564641b9ae25ac2c7a9a851e8ae5a80c43c2cf9d.c935
-rw-r--r--syzkaller-repros/linux/565bdd2c27a6fc76117fac4671e984f39cb886f7.c316
-rw-r--r--syzkaller-repros/linux/56edf911a2fb841c33f8eb962efb2c5c2f45514d.c48
-rw-r--r--syzkaller-repros/linux/57f0d245a292ce33a1f0abd020f297e8601ecf21.c612
-rw-r--r--syzkaller-repros/linux/586245a7ce8d813f1f34ddd58d77bbc56222e67f.c443
-rw-r--r--syzkaller-repros/linux/588bf3cdaa258c756363aaa58b3cc56f08617cae.c578
-rw-r--r--syzkaller-repros/linux/59ba2f79c97f0c49dfcdf15e4f26aca3b8ffa76e.c322
-rw-r--r--syzkaller-repros/linux/5bb058155a1d145f0c26b6a32cd27eeb9950ee11.c688
-rw-r--r--syzkaller-repros/linux/5bb56c5cdf046394533740ed1009789377b7f35a.c31
-rw-r--r--syzkaller-repros/linux/5c0c25a33eb0651a5b2bdbc944372992dad91a4b.c742
-rw-r--r--syzkaller-repros/linux/5c4510d56c0a8388beb359182cf651407f669ed8.c402
-rw-r--r--syzkaller-repros/linux/5c7b138065ace9d3f00c0d0fffef2f6854c56a00.c1219
-rw-r--r--syzkaller-repros/linux/5d77610aeaaeddfa55c57a964fb4f4ae7e08c30c.c484
-rw-r--r--syzkaller-repros/linux/5d79326609112f7037a8f97b02d1ccccc1da943e.c34
-rw-r--r--syzkaller-repros/linux/5e57e5f0dc65684681141a35c4f202efe41b2578.c577
-rw-r--r--syzkaller-repros/linux/5ed56f4caf5b58ccf3c013d5798b2fb61b40eba8.c1107
-rw-r--r--syzkaller-repros/linux/5fe2408910fc851794ba02c468fabe70c56ea3b6.c425
-rw-r--r--syzkaller-repros/linux/60c210359008690dc9061473b0307f2ec1e55f71.c326
-rw-r--r--syzkaller-repros/linux/6117de858dc67fea5b42b327761d2fb973c32fcc.c433
-rw-r--r--syzkaller-repros/linux/64652ef82318ae833b252bb22dc16e13f344d6d5.c511
-rw-r--r--syzkaller-repros/linux/64c6ad900871a32499005fa874244be1847e3b2c.c405
-rw-r--r--syzkaller-repros/linux/6592b2397fe3d588ba3d54d3cc48a769a300c2a1.c118
-rw-r--r--syzkaller-repros/linux/6665a2e0c54f2675589258ad04ffa1e5fc76f071.c413
-rw-r--r--syzkaller-repros/linux/666cf8be893ec25bbf0e3ed7596dc30e1f3518ba.c616
-rw-r--r--syzkaller-repros/linux/66ab7d59ba4e2b4d7cb27ea0561db6eeaf272b61.c900
-rw-r--r--syzkaller-repros/linux/67748d865de4a2d605805e74d2c16adc6d7bf8ed.c319
-rw-r--r--syzkaller-repros/linux/679c09d7d8ae7850343c817c27bde5d9bd20d981.c294
-rw-r--r--syzkaller-repros/linux/68019ecadea1dc5071dccdd4450e9fb378c45f05.c453
-rw-r--r--syzkaller-repros/linux/684acfc05e01c6b53ea2b2034758dac4c39f9ac8.c1031
-rw-r--r--syzkaller-repros/linux/685cea42775bcc9dbb3e2465b643e2fb098e961d.c142
-rw-r--r--syzkaller-repros/linux/699d00fe76ebc818fa6fb822b14ca79c0bf10ae4.c380
-rw-r--r--syzkaller-repros/linux/6ba1a7dced6ab743cf2068c4eb61286dbc50cd6f.c1874
-rw-r--r--syzkaller-repros/linux/6c8a755e7ac31a5dfbb699fe8d5da4c0bdab6ab1.c55
-rw-r--r--syzkaller-repros/linux/6ca587f7c057c003d5aba08d470e22fa0047a1ee.c501
-rw-r--r--syzkaller-repros/linux/6e89ce80a10c14d6e832ef9b558bcd045825e05b.c297
-rw-r--r--syzkaller-repros/linux/6ea7a0d0da1c0753938590eb42022ac3066ea3f0.c546
-rw-r--r--syzkaller-repros/linux/6f26ec1b91269a365ebc62728c35e83fc8fcb1ad.c1127
-rw-r--r--syzkaller-repros/linux/6f63dd43a3128aad6ccc78b0fdac97d714dae9ec.c125
-rw-r--r--syzkaller-repros/linux/7108e32817eabfa942ef178898bfcc9665357b30.c102
-rw-r--r--syzkaller-repros/linux/7178f5e3c9146fc84a07bc87e3b40aa0b2fabe03.c460
-rw-r--r--syzkaller-repros/linux/719d1c9a51751d6211725dd768a22aac812d5c16.c66
-rw-r--r--syzkaller-repros/linux/72c38236aec3b42af48cc5b21c0dca0d536efcab.c254
-rw-r--r--syzkaller-repros/linux/73442781849194e635547ef76611d132f9e3458f.c270
-rw-r--r--syzkaller-repros/linux/73635912ce586acdaa2cbe4206fa1414b095e6a1.c285
-rw-r--r--syzkaller-repros/linux/7472331ea05c4d9bef2d34636f5941e800dee7cd.c684
-rw-r--r--syzkaller-repros/linux/7549a7ef3c7db3bf65acad1f27c5dba18f8d9bee.c168
-rw-r--r--syzkaller-repros/linux/78456bb7e9b0e4c786f3b5452e83978e2d249804.c454
-rw-r--r--syzkaller-repros/linux/7a326b12c63a0cb0927b54486cc88e12e7d296d5.c230
-rw-r--r--syzkaller-repros/linux/7b1d73f9b987611883418c85c23926a2a3ed3853.c533
-rw-r--r--syzkaller-repros/linux/7caa19bc225b467b96fe870bb2f33d2278ee2eed.c210
-rw-r--r--syzkaller-repros/linux/7cbb8a66a79c83d5e96c8aad6b16d5791f738c74.c607
-rw-r--r--syzkaller-repros/linux/7cc74fe65940458cb736edab0104aa2cf53faea1.c230
-rw-r--r--syzkaller-repros/linux/7fd99cec32407752014226ed25778bd75b6d322f.c348
-rw-r--r--syzkaller-repros/linux/804f59cfabd90cf56da1d83c9fdc19267fbfc0f8.c256
-rw-r--r--syzkaller-repros/linux/82cfa36c1b9421e6e4148cca731f7ef35c0080a8.c59
-rw-r--r--syzkaller-repros/linux/84565948d3b91a924f2a3723e1c60b40248ab2f4.c447
-rw-r--r--syzkaller-repros/linux/84f365fefa97fd8af5d1de35909ae9ac93bb5c79.c1114
-rw-r--r--syzkaller-repros/linux/8526f2731ca76af1808f6408d11a5accd819572a.c617
-rw-r--r--syzkaller-repros/linux/857b4cdfac73d5ae10e85a3f30cf370529df0d37.c237
-rw-r--r--syzkaller-repros/linux/87d3bf6296c859d92186a158d189fb1b4119c59e.c503
-rw-r--r--syzkaller-repros/linux/8a67302e1043ae88b584e8f44db150de4b3e9e46.c161
-rw-r--r--syzkaller-repros/linux/8ab5d21faf80f1ee44314d64c330e91676c48d0c.c140
-rw-r--r--syzkaller-repros/linux/8afcfa289eecd61a16a7b15a7d5b8fd31b9500cb.c64
-rw-r--r--syzkaller-repros/linux/8b36a396ec6f779c412e50ecb320b66b67569099.c303
-rw-r--r--syzkaller-repros/linux/8c1106a7287dc1cdbfc455097ddfab8faeb5ffcb.c737
-rw-r--r--syzkaller-repros/linux/8d186fae388cadf8b664d5d74214851c2855d2db.c223
-rw-r--r--syzkaller-repros/linux/917103403545122e58fa7f05f5e27e26d1b44b4e.c439
-rw-r--r--syzkaller-repros/linux/938eac2e752cc83e060a5c9fc3be0e83edeb687b.c431
-rw-r--r--syzkaller-repros/linux/939673fcc99d8c8ac52a3d4d9862bd1748bab317.c317
-rw-r--r--syzkaller-repros/linux/944b6e7cbd6c173d7f8dffd5e1715c2e25c71d5c.c204
-rw-r--r--syzkaller-repros/linux/95419b31bfb7783adfd504d4b3ea5f646366e8a9.c34
-rw-r--r--syzkaller-repros/linux/98341f62c64fb33877d1996dcce6b2e931c26a2d.c759
-rw-r--r--syzkaller-repros/linux/983b5307cfcad4e74e3dcb1dcacf7f4302aab03b.c1146
-rw-r--r--syzkaller-repros/linux/98b14adec5e7c3a28f76e2ac90de27b064bfd9d6.c1467
-rw-r--r--syzkaller-repros/linux/997f131c54f3af896f51a273b479033ac59eca54.c219
-rw-r--r--syzkaller-repros/linux/99fed9c49f1dcedc898556e2bfc2214578fbfc4f.c79
-rw-r--r--syzkaller-repros/linux/9ca49645a6602cde90a9f62497d1b4f1a3dfdc31.c244
-rw-r--r--syzkaller-repros/linux/9ccfdd8b47bdb95ad17277f7c1b055c4dcef1bfe.c50
-rw-r--r--syzkaller-repros/linux/9dfe96b48c8570c16eb2f2c874b494731d5de11a.c372
-rw-r--r--syzkaller-repros/linux/9f4072db0f477dd9e755f50a2186a4c8cd377c64.c238
-rw-r--r--syzkaller-repros/linux/9f97c7066f70c61e5d9d42da3ccd5917ec81c8b2.c269
-rw-r--r--syzkaller-repros/linux/9fd843999c6e320661905cafc1eb3e9b36691e63.c207
-rw-r--r--syzkaller-repros/linux/a61c70e69cc9cbf670a632d0fd1457d3718c66f8.c459
-rw-r--r--syzkaller-repros/linux/a82ff8cfa42fa8b5986b3ff2454f2e435a2a8706.c441
-rw-r--r--syzkaller-repros/linux/a8ad6862817edd0b631f8547843c684f45e09bd1.c321
-rw-r--r--syzkaller-repros/linux/ab2ce52e17c561fe15b48290dd8f0f31770983f3.c363
-rw-r--r--syzkaller-repros/linux/aba7fea369c95764f5bdb4bde7d65c40bb033de9.c117
-rw-r--r--syzkaller-repros/linux/ac95a2efec88d8b83a87f1d7b75dee8adbe605bc.c294
-rw-r--r--syzkaller-repros/linux/ad8204ca57a1325744c730504d3a1db01b02ece7.c899
-rw-r--r--syzkaller-repros/linux/aeedb5a72e90166ad43d01ef7903a82e3bb152f2.c221
-rw-r--r--syzkaller-repros/linux/aef49c1a69a0735d29caaaddc7819aaed6c8c501.c1083
-rw-r--r--syzkaller-repros/linux/aff4be9963d14b033e496164b2fdb16fd437bbe8.c449
-rw-r--r--syzkaller-repros/linux/aff5959c1d4af7564287846f796ff7b8462352ed.c668
-rw-r--r--syzkaller-repros/linux/b06c3d8398b9cdd888c8404b690cb7aa3ec1b0fc.c231
-rw-r--r--syzkaller-repros/linux/b15b71cdbabd376770788544e17a585a9ed0de7e.c377
-rw-r--r--syzkaller-repros/linux/b1749b0ecbd1cc9fb2350136237de3217b0a6877.c375
-rw-r--r--syzkaller-repros/linux/b2846c7751a664d14ed5bfde51972a0be01d59b5.c1010
-rw-r--r--syzkaller-repros/linux/b304e48c105e40ff49f5da148009e29029e0431b.c205
-rw-r--r--syzkaller-repros/linux/b482c6fe08771a40799a9f1493ed89eab15317df.c945
-rw-r--r--syzkaller-repros/linux/b4898106f15c86708a41b4f8289636f891305544.c353
-rw-r--r--syzkaller-repros/linux/b4d4d45523ff8bd6037cdda888b1f324e3bd790d.c525
-rw-r--r--syzkaller-repros/linux/b5d9f4bd1577a82194bb194ab17ff01022a39827.c675
-rw-r--r--syzkaller-repros/linux/b641a2146b1768b13e6c37113f601f4a4ee5c639.c210
-rw-r--r--syzkaller-repros/linux/b6e19a81ffabd2d0ee90b113fbadcfde65588f93.c235
-rw-r--r--syzkaller-repros/linux/b701a1c2840d516fe41ed0bd76c4a0216061a4ef.c303
-rw-r--r--syzkaller-repros/linux/b73bb88d699a3274fc7d1fcd654b5cdf4a2c4ef1.c613
-rw-r--r--syzkaller-repros/linux/b7d5993be89a011ed89a6f4fb13bf0499ee236e7.c1104
-rw-r--r--syzkaller-repros/linux/bafbad01f8de79fea86449546cb55ea6123f7edc.c432
-rw-r--r--syzkaller-repros/linux/bbce98d65a84c401f0ba39d002f01d47f32492af.c316
-rw-r--r--syzkaller-repros/linux/bcda6447d0e4d143d651f4de1db156bde861a3b9.c1346
-rw-r--r--syzkaller-repros/linux/bd080858553377ac37175467b7a5dc01e9f499a5.c92
-rw-r--r--syzkaller-repros/linux/bddc7437dcb91ae53a0fd9672468ccd1152b1b4b.c58
-rw-r--r--syzkaller-repros/linux/be160e6f498300a335023b6b0e33fa4a0c9f2822.c283
-rw-r--r--syzkaller-repros/linux/bebad04768179c04b412f52d590e74b7200d383f.c678
-rw-r--r--syzkaller-repros/linux/bf3a6f60ba6ab6a233284f7a1fd52eadacf26bb4.c578
-rw-r--r--syzkaller-repros/linux/c1dd10546a0f52f25a2cd1eee8596c6e09eece6d.c157
-rw-r--r--syzkaller-repros/linux/c37ecd4167eea34e634df7261019d07996dfec9e.c461
-rw-r--r--syzkaller-repros/linux/c3960c948f92ebce8f1790d87d20ad6d0a8befa8.c473
-rw-r--r--syzkaller-repros/linux/c3c734ede90bc97ce7a49fa266e7e6ac275ac15c.c278
-rw-r--r--syzkaller-repros/linux/c43d832d97fb6f646cee396845c6f7a1a625559e.c134
-rw-r--r--syzkaller-repros/linux/c47b1b7f05e955d0f05419eadbdf5bf7c2d9ae00.c426
-rw-r--r--syzkaller-repros/linux/c765b46408bf5af4eace4188e78ec21cc1c93a0c.c879
-rw-r--r--syzkaller-repros/linux/c89260cf352b3c907c9899403b65727b666b591c.c314
-rw-r--r--syzkaller-repros/linux/c9da3c745a77c2b3b286c9261e808853ae4b4304.c307
-rw-r--r--syzkaller-repros/linux/cabdcf8dab83f89b7efe104a10de67a17f1ab902.c47
-rw-r--r--syzkaller-repros/linux/cbb7dab789d8f23306187cfc894a5a65d02b6e95.c605
-rw-r--r--syzkaller-repros/linux/ccd3afec24eaa9bb5ca67bc5098f274107a621b3.c148
-rw-r--r--syzkaller-repros/linux/d1e22c7dfb66c4f88fdf305ee211f0f0a099c647.c864
-rw-r--r--syzkaller-repros/linux/d247615dab7b953b6787c9f5cfbd0c0bd4007a2d.c592
-rw-r--r--syzkaller-repros/linux/d25f08af566d1bbff3646aa29b49998d705d53e3.c137
-rw-r--r--syzkaller-repros/linux/d31813ba6b649194a2284b8e860326f1fe919d0c.c452
-rw-r--r--syzkaller-repros/linux/d42c5e0bf62a0373f9fe4ad941b5bcd8f48e79d8.c494
-rw-r--r--syzkaller-repros/linux/d50415e7b7b96bf0167377b93aa5ab497e534a27.c58
-rw-r--r--syzkaller-repros/linux/d5b4a3660a50244c4ff02f404c21e30f54f86c06.c107
-rw-r--r--syzkaller-repros/linux/d67643a91b624d26806fec135662c57038a4eda7.c123
-rw-r--r--syzkaller-repros/linux/d678bac282884bdebf54dcba95f494209d35c4ac.c92
-rw-r--r--syzkaller-repros/linux/d83b8c5a988c2fb1aa02dca97af8e4db823f0429.c442
-rw-r--r--syzkaller-repros/linux/d9776b55c9e677e21256ad05a2a157806e4d79c7.c245
-rw-r--r--syzkaller-repros/linux/dadeca0bd04f4d6328cfe8197796f6bb71ee9594.c767
-rw-r--r--syzkaller-repros/linux/db5c0b369f0a94927e3d09cefcccf8871898b64b.c34
-rw-r--r--syzkaller-repros/linux/dc6d400c372e699f23dcc717591d6b66152a6dba.c1521
-rw-r--r--syzkaller-repros/linux/e02d0c83bf477ef195f4080ed7c0339a86b10f27.c28
-rw-r--r--syzkaller-repros/linux/e07ae74f38e943b1838e053e3204b480235c6b31.c198
-rw-r--r--syzkaller-repros/linux/e24f0807cf78061bdbe5e9ca08df641fe4f33126.c241
-rw-r--r--syzkaller-repros/linux/e4432806b1b9c791b6c3185785fcdbdcd8054d4f.c82
-rw-r--r--syzkaller-repros/linux/e4e5a43811c434e39a8ffd0c4913f213172c77c3.c286
-rw-r--r--syzkaller-repros/linux/e53e20188ca052347cbbade1b1c1c9683991239e.c422
-rw-r--r--syzkaller-repros/linux/e6328edb1d91b5af561439aded6a7d4cb671a90c.c259
-rw-r--r--syzkaller-repros/linux/e955f8f41c1f05c49439ac95657f0e4df562ad55.c342
-rw-r--r--syzkaller-repros/linux/e9b0acb3f0bfed98df05a70d835d3f014bafa045.c204
-rw-r--r--syzkaller-repros/linux/e9f5b11984c54cecb386b92bb20c76d5d003719f.c60
-rw-r--r--syzkaller-repros/linux/ea9509cd83e4b2e27f8a9bfbd92c8fd7de381da9.c769
-rw-r--r--syzkaller-repros/linux/ec4dcfe1da2f9c2560285cf6033991a2ad84950d.c226
-rw-r--r--syzkaller-repros/linux/edbf736874b3fd00db172173256731c6b1123883.c201
-rw-r--r--syzkaller-repros/linux/efb8c5fe01ecb5116825ce2409485c164c048f88.c245
-rw-r--r--syzkaller-repros/linux/efdaf08406adeccaf182b7a15193f0f71e44bbca.c20
-rw-r--r--syzkaller-repros/linux/f083f6f60c98f51945eb4ec80c1d06ea6bd0e9de.c359
-rw-r--r--syzkaller-repros/linux/f1207160d29ff8806029b7233fd54322d44f6572.c296
-rw-r--r--syzkaller-repros/linux/f46698eabd542bcae3e24d1be3d179a23cd7c6eb.c307
-rw-r--r--syzkaller-repros/linux/f56ab692e7055a5edf3da099ae9c11d21242c42d.c1050
-rw-r--r--syzkaller-repros/linux/f5705df7b6e0573321a2e322ef7e0d3af68cea1a.c20
-rw-r--r--syzkaller-repros/linux/f57556adc921a352d4449d9bc8569d9f08fe0da3.c321
-rw-r--r--syzkaller-repros/linux/f711915bab4424dc49beba5ac02e23e6c906449c.c245
-rw-r--r--syzkaller-repros/linux/f73b3116ad434cc9b97b908060b5e73752df3be7.c386
-rw-r--r--syzkaller-repros/linux/f77562bab0c7b54949eeb4f670a42406ebe6987c.c530
-rw-r--r--syzkaller-repros/linux/f7b9b47b8a12b6ff7a434d6f908d38699e08ada0.c612
-rw-r--r--syzkaller-repros/linux/f7e0bba8c3e53fe21a4a60bc232356b7d704f634.c446
-rw-r--r--syzkaller-repros/linux/f7f424f89ff5d010aefc0ae8cfeeb1186bcfd0da.c1198
-rw-r--r--syzkaller-repros/linux/f8725c52685453f7bc7ca68e1d7abaf7bd01c124.c1048
-rw-r--r--syzkaller-repros/linux/f8ce2875913eb4d65cd6ece71108d9d8e863469a.c190
-rw-r--r--syzkaller-repros/linux/f9b1382ef613844e96f73867e9b946aec9774fd6.c433
-rw-r--r--syzkaller-repros/linux/f9d67ee369f3db72fa6adaaf0c0000a3b8052d2d.c819
-rw-r--r--syzkaller-repros/linux/fa9f4a0c5b1dc84273298312286f4c7ad1721698.c91
-rw-r--r--syzkaller-repros/linux/ff30bd33030b8fd539566a6faf8ece5650b1038e.c1618
270 files changed, 128683 insertions, 0 deletions
diff --git a/syzkaller-repros/linux/0139a1a5c800cb341ec87d5b6f92ee2a6e505b16.c b/syzkaller-repros/linux/0139a1a5c800cb341ec87d5b6f92ee2a6e505b16.c
new file mode 100644
index 0000000..e4e72fd
--- /dev/null
+++ b/syzkaller-repros/linux/0139a1a5c800cb341ec87d5b6f92ee2a6e505b16.c
@@ -0,0 +1,1609 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 25; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[10] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000140, "./bus\000", 6);
+ res = syscall(__NR_open, 0x20000140ul, 0x141042ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ res = syscall(__NR_socket, 0xaul, 1ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ res = syscall(__NR_dup2, r[1], r[1]);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 3:
+ syscall(__NR_setsockopt, r[2], 0ul, 0x40ul, 0ul, 0ul);
+ break;
+ case 4:
+ res = syscall(__NR_accept4, r[2], 0ul, 0ul, 0x80000ul);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 5:
+ res = syscall(__NR_socket, 0xaul, 1ul, 0ul);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 6:
+ syscall(__NR_ioctl, r[0], 0x8904ul, 0ul);
+ break;
+ case 7:
+ *(uint32_t*)0x20000440 = 0;
+ *(uint32_t*)0x20000444 = 0x70;
+ *(uint8_t*)0x20000448 = 0;
+ *(uint8_t*)0x20000449 = 0xf8;
+ *(uint8_t*)0x2000044a = 0xf9;
+ *(uint8_t*)0x2000044b = 3;
+ *(uint32_t*)0x2000044c = 0;
+ *(uint64_t*)0x20000450 = 3;
+ *(uint64_t*)0x20000458 = 0x8eae8d1ce7182c60;
+ *(uint64_t*)0x20000460 = 2;
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 0, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 1, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 2, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 3, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 4, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 5, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 6, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 7, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 8, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 9, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 10, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 11, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 12, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 13, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 14, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 15, 2);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 17, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 18, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 19, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 20, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 21, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 22, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 23, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 1, 24, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 25, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 26, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 27, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 28, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x20000468, 0, 29, 35);
+ *(uint32_t*)0x20000470 = 0x29;
+ *(uint32_t*)0x20000474 = 4;
+ *(uint64_t*)0x20000478 = 0x1000;
+ *(uint64_t*)0x20000480 = 5;
+ *(uint64_t*)0x20000488 = 1;
+ *(uint64_t*)0x20000490 = 0x80000001;
+ *(uint32_t*)0x20000498 = 5;
+ *(uint32_t*)0x2000049c = 0;
+ *(uint64_t*)0x200004a0 = 0x80;
+ *(uint32_t*)0x200004a8 = 0xfffffffe;
+ *(uint16_t*)0x200004ac = 5;
+ *(uint16_t*)0x200004ae = 0;
+ syscall(__NR_perf_event_open, 0x20000440ul, 0, 0xeul, r[2], 0xbul);
+ break;
+ case 8:
+ res = syscall(__NR_dup2, r[4], r[4]);
+ if (res != -1)
+ r[5] = res;
+ break;
+ case 9:
+ syscall(__NR_fcntl, r[4], 0x10ul, 0ul);
+ break;
+ case 10:
+ syscall(__NR_fcntl, r[3], 0xful, 0ul);
+ break;
+ case 11:
+ memcpy((void*)0x20000300, "./file0\000", 8);
+ res = syscall(__NR_creat, 0x20000300ul, 0ul);
+ if (res != -1)
+ r[6] = res;
+ break;
+ case 12:
+ *(uint32_t*)0x20000280 = 1;
+ *(uint8_t*)0x20000284 = 0x7b;
+ *(uint16_t*)0x20000285 = 0;
+ syscall(__NR_write, r[6], 0x20000280ul, 0xff7ful);
+ break;
+ case 13:
+ memcpy((void*)0x20000700, "./bus\000", 6);
+ res = syscall(__NR_creat, 0x20000700ul, 0ul);
+ if (res != -1)
+ r[7] = res;
+ break;
+ case 14:
+ syscall(__NR_ftruncate, -1, 0x2081fcul);
+ break;
+ case 15:
+ memcpy((void*)0x20000240, "./file0\000", 8);
+ res = syscall(__NR_open, 0x20000240ul, 0x20141042ul, 0ul);
+ if (res != -1)
+ r[8] = res;
+ break;
+ case 16:
+ syscall(__NR_ioctl, r[0], 0x227dul, 0ul);
+ break;
+ case 17:
+ syscall(__NR_ioctl, -1, 0xc014563bul, 0ul);
+ break;
+ case 18:
+ syscall(__NR_mmap, 0x20003000ul, 0x3000ul, 0x800002ul, 0x11ul, r[8], 0);
+ break;
+ case 19:
+ syscall(__NR_fcntl, r[5], 4ul, 0x22c00ul);
+ break;
+ case 20:
+ memcpy((void*)0x20000200, "threaded\000", 9);
+ syscall(__NR_write, r[7], 0x20000200ul, 0xf642e7eul);
+ break;
+ case 21:
+ *(uint32_t*)0x20000200 = 0;
+ *(uint32_t*)0x20000204 = r[6];
+ *(uint64_t*)0x20000208 = 0;
+ *(uint64_t*)0x20000210 = 0;
+ *(uint64_t*)0x20000218 = 0;
+ *(uint64_t*)0x20000220 = 0;
+ syscall(__NR_ioctl, r[0], 0xc028660ful, 0x20000200ul);
+ break;
+ case 22:
+ res = syscall(__NR_socket, 0x2cul, 3ul, 0ul);
+ if (res != -1)
+ r[9] = res;
+ break;
+ case 23:
+ *(uint64_t*)0x200000c0 = 0x20000000;
+ *(uint64_t*)0x200000c8 = 0x20000;
+ *(uint32_t*)0x200000d0 = 0x1000;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ syscall(__NR_setsockopt, r[9], 0x11bul, 4ul, 0x200000c0ul, 0x18ul);
+ break;
+ case 24:
+ syscall(__NR_bind, -1, 0ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/01e50119f4515ff34aca0aff7b80c67196cb5c43.c b/syzkaller-repros/linux/01e50119f4515ff34aca0aff7b80c67196cb5c43.c
new file mode 100644
index 0000000..9f904f7
--- /dev/null
+++ b/syzkaller-repros/linux/01e50119f4515ff34aca0aff7b80c67196cb5c43.c
@@ -0,0 +1,117 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x64;
+ *(uint8_t*)0x20000004 = 2;
+ *(uint8_t*)0x20000005 = 6;
+ *(uint16_t*)0x20000006 = 1;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 0;
+ *(uint16_t*)0x20000012 = htobe16(0);
+ *(uint16_t*)0x20000014 = 0xe;
+ *(uint16_t*)0x20000016 = 3;
+ memcpy((void*)0x20000018, "bitmap:ip\000", 10);
+ *(uint16_t*)0x20000024 = 9;
+ *(uint16_t*)0x20000026 = 2;
+ memcpy((void*)0x20000028, "syz1\000", 5);
+ *(uint16_t*)0x20000030 = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x20000032, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000033, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000033, 1, 7, 1);
+ *(uint16_t*)0x20000034 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000036, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000037, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000037, 1, 7, 1);
+ *(uint16_t*)0x20000038 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000003a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000003b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000003b, 0, 7, 1);
+ *(uint32_t*)0x2000003c = htobe32(0);
+ *(uint16_t*)0x20000040 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000042, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000043, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000043, 1, 7, 1);
+ *(uint16_t*)0x20000044 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000046, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000047, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000047, 0, 7, 1);
+ *(uint32_t*)0x20000048 = htobe32(0);
+ *(uint16_t*)0x2000004c = 5;
+ *(uint16_t*)0x2000004e = 1;
+ *(uint8_t*)0x20000050 = 7;
+ *(uint16_t*)0x20000054 = 5;
+ *(uint16_t*)0x20000056 = 4;
+ *(uint8_t*)0x20000058 = 0;
+ *(uint16_t*)0x2000005c = 5;
+ *(uint16_t*)0x2000005e = 5;
+ *(uint8_t*)0x20000060 = 2;
+ *(uint64_t*)0x200002c8 = 0x64;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x200003c0 = 0;
+ *(uint32_t*)0x200003c8 = 0;
+ *(uint64_t*)0x200003d0 = 0x20000380;
+ *(uint64_t*)0x20000380 = 0x20000180;
+ *(uint32_t*)0x20000180 = 0x24;
+ *(uint8_t*)0x20000184 = 7;
+ *(uint8_t*)0x20000185 = 6;
+ *(uint16_t*)0x20000186 = 0x301;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint32_t*)0x2000018c = 0;
+ *(uint8_t*)0x20000190 = 1;
+ *(uint8_t*)0x20000191 = 0;
+ *(uint16_t*)0x20000192 = htobe16(0);
+ *(uint16_t*)0x20000194 = 5;
+ *(uint16_t*)0x20000196 = 1;
+ *(uint8_t*)0x20000198 = 7;
+ *(uint16_t*)0x2000019c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000019e, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019f, 0, 7, 1);
+ *(uint32_t*)0x200001a0 = htobe32(8);
+ *(uint64_t*)0x20000388 = 0x24;
+ *(uint64_t*)0x200003d8 = 1;
+ *(uint64_t*)0x200003e0 = 0;
+ *(uint64_t*)0x200003e8 = 0;
+ *(uint32_t*)0x200003f0 = 0x11;
+ syscall(__NR_sendmsg, r[1], 0x200003c0ul, 0x10ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/03ee30ae11dfd0ddd062af26566c34a8c853698d.c b/syzkaller-repros/linux/03ee30ae11dfd0ddd062af26566c34a8c853698d.c
new file mode 100644
index 0000000..b843d74
--- /dev/null
+++ b/syzkaller-repros/linux/03ee30ae11dfd0ddd062af26566c34a8c853698d.c
@@ -0,0 +1,824 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static long syz_init_net_socket(volatile long domain, volatile long type,
+ volatile long proto)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ return netns;
+ if (setns(kInitNetNsFd, 0))
+ return -1;
+ int sock = syscall(__NR_socket, domain, type, proto);
+ int err = errno;
+ if (setns(netns, 0))
+ exit(1);
+ close(netns);
+ errno = err;
+ return sock;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syz_init_net_socket(9, 5, 0);
+ if (res != -1)
+ r[0] = res;
+ memcpy(
+ (void*)0x20000180,
+ "eth0\000\000\000\000\000\000\000\000\000\000\r\273?\211\000\000\000 "
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\001\000\000\000\000\000\000\000\032\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000$"
+ "\000\000\000\000\000\000\000\000\000\000\377\027\000\000\000\000\000\000"
+ "\000\000\000\002\000\000S0\000\000\000\000\000\000\000\000\000\000_/"
+ "0\304\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000",
+ 192);
+ *(uint64_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ syscall(__NR_ioctl, r[0], 0x8949ul, 0x20000180ul);
+ res = syz_init_net_socket(0x1a, 2, 0);
+ if (res != -1)
+ r[1] = res;
+ *(uint32_t*)0x200000c0 = 7;
+ syscall(__NR_setsockopt, r[1], 1ul, 0x3eul, 0x200000c0ul, 4ul);
+ *(uint16_t*)0x20000040 = 0x1a;
+ *(uint16_t*)0x20000042 = 0;
+ *(uint8_t*)0x20000044 = 0;
+ *(uint8_t*)0x20000045 = 0;
+ *(uint8_t*)0x20000046 = 0;
+ *(uint8_t*)0x20000047 = 0;
+ *(uint8_t*)0x20000048 = 0;
+ *(uint8_t*)0x20000049 = 0;
+ *(uint8_t*)0x2000004a = 0;
+ *(uint8_t*)0x2000004b = 0;
+ *(uint8_t*)0x2000004c = 0;
+ *(uint8_t*)0x2000004d = 0;
+ syscall(__NR_bind, r[1], 0x20000040ul, 0x10ul);
+ syscall(__NR_sendmmsg, r[1], 0x20001380ul, 0x3fffffffffffeedul, 0ul);
+ close_fds();
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0401d67c3c0ebbc0a5dbe2167c81376013a31fe4.c b/syzkaller-repros/linux/0401d67c3c0ebbc0a5dbe2167c81376013a31fe4.c
new file mode 100644
index 0000000..90a0c75
--- /dev/null
+++ b/syzkaller-repros/linux/0401d67c3c0ebbc0a5dbe2167c81376013a31fe4.c
@@ -0,0 +1,294 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20001080 = 0;
+ *(uint32_t*)0x20001088 = 0;
+ *(uint64_t*)0x20001090 = 0x20001040;
+ *(uint64_t*)0x20001040 = 0x200002c0;
+ *(uint32_t*)0x200002c0 = 0x48;
+ *(uint8_t*)0x200002c4 = 2;
+ *(uint8_t*)0x200002c5 = 6;
+ *(uint16_t*)0x200002c6 = 1;
+ *(uint32_t*)0x200002c8 = 0;
+ *(uint32_t*)0x200002cc = 0;
+ *(uint8_t*)0x200002d0 = 0;
+ *(uint8_t*)0x200002d1 = 0;
+ *(uint16_t*)0x200002d2 = htobe16(0);
+ *(uint16_t*)0x200002d4 = 0xd;
+ *(uint16_t*)0x200002d6 = 3;
+ memcpy((void*)0x200002d8, "list:set\000", 9);
+ *(uint16_t*)0x200002e4 = 5;
+ *(uint16_t*)0x200002e6 = 4;
+ *(uint8_t*)0x200002e8 = 0;
+ *(uint16_t*)0x200002ec = 5;
+ *(uint16_t*)0x200002ee = 5;
+ *(uint8_t*)0x200002f0 = 0;
+ *(uint16_t*)0x200002f4 = 9;
+ *(uint16_t*)0x200002f6 = 2;
+ memcpy((void*)0x200002f8, "syz1\000", 5);
+ *(uint16_t*)0x20000300 = 5;
+ *(uint16_t*)0x20000302 = 1;
+ *(uint8_t*)0x20000304 = 7;
+ *(uint64_t*)0x20001048 = 0x48;
+ *(uint64_t*)0x20001098 = 1;
+ *(uint64_t*)0x200010a0 = 0;
+ *(uint64_t*)0x200010a8 = 0;
+ *(uint32_t*)0x200010b0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20001080ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000340 = 0;
+ *(uint32_t*)0x20000348 = 0;
+ *(uint64_t*)0x20000350 = 0x20000300;
+ *(uint64_t*)0x20000300 = 0x20000140;
+ *(uint32_t*)0x20000140 = 0x1a4;
+ *(uint8_t*)0x20000144 = 0xb;
+ *(uint8_t*)0x20000145 = 6;
+ *(uint16_t*)0x20000146 = 1;
+ *(uint32_t*)0x20000148 = 0x70bd27;
+ *(uint32_t*)0x2000014c = 0x25dfdbfb;
+ *(uint8_t*)0x20000150 = 0xa;
+ *(uint8_t*)0x20000151 = 0;
+ *(uint16_t*)0x20000152 = htobe16(8);
+ *(uint16_t*)0x20000154 = 0x54;
+ STORE_BY_BITMASK(uint16_t, , 0x20000156, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000157, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000157, 1, 7, 1);
+ *(uint16_t*)0x20000158 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x2000015a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000015b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000015b, 1, 7, 1);
+ *(uint16_t*)0x2000015c = 0x14;
+ *(uint16_t*)0x2000015e = 2;
+ memcpy((void*)0x20000160,
+ "\xae\x14\x6d\x52\x25\xc9\x52\x45\x57\x98\xc3\xce\x32\x1f\xe8\x6a",
+ 16);
+ *(uint16_t*)0x20000170 = 9;
+ *(uint16_t*)0x20000172 = 0x13;
+ memcpy((void*)0x20000174, "syz1\000", 5);
+ *(uint16_t*)0x2000017c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000017e, 0xb, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000017f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000017f, 0, 7, 1);
+ *(uint32_t*)0x20000180 = htobe32(4);
+ *(uint16_t*)0x20000184 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x20000186, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000187, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000187, 0, 7, 1);
+ *(uint16_t*)0x20000188 = htobe16(0x4e24);
+ *(uint16_t*)0x2000018c = 0x14;
+ *(uint16_t*)0x2000018e = 0x17;
+ memcpy((void*)0x20000190, "bond_slave_0\000\000\000\000", 16);
+ *(uint16_t*)0x200001a0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001a2, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 0, 7, 1);
+ *(uint32_t*)0x200001a4 = htobe32(3);
+ *(uint16_t*)0x200001a8 = 0x54;
+ STORE_BY_BITMASK(uint16_t, , 0x200001aa, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001ab, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001ab, 1, 7, 1);
+ *(uint16_t*)0x200001ac = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ae, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001af, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001af, 1, 7, 1);
+ *(uint16_t*)0x200001b0 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x200001b2, 0x1d, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001b3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001b3, 0, 7, 1);
+ *(uint16_t*)0x200001b4 = htobe16(0xaf);
+ *(uint16_t*)0x200001b8 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ba, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001bb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001bb, 1, 7, 1);
+ *(uint16_t*)0x200001bc = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001be, 0x18, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001bf, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001bf, 0, 7, 1);
+ *(uint64_t*)0x200001c0 = htobe64(1);
+ *(uint16_t*)0x200001c8 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ca, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001cb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001cb, 1, 7, 1);
+ *(uint16_t*)0x200001cc = 5;
+ *(uint16_t*)0x200001ce = 0x1a;
+ memcpy((void*)0x200001d0, "\000", 1);
+ *(uint16_t*)0x200001d4 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x200001d6, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001d7, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001d7, 1, 7, 1);
+ *(uint16_t*)0x200001d8 = 9;
+ *(uint16_t*)0x200001da = 0x12;
+ memcpy((void*)0x200001dc, "syz2\000", 5);
+ *(uint16_t*)0x200001e4 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001e6, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001e7, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001e7, 1, 7, 1);
+ *(uint16_t*)0x200001e8 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ea, 0x1d, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001eb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001eb, 0, 7, 1);
+ *(uint16_t*)0x200001ec = htobe16(5);
+ *(uint16_t*)0x200001f0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001f2, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001f3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001f3, 1, 7, 1);
+ *(uint16_t*)0x200001f4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001f6, 0x1c, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001f7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001f7, 0, 7, 1);
+ *(uint32_t*)0x200001f8 = htobe32(2);
+ *(uint16_t*)0x200001fc = 9;
+ *(uint16_t*)0x200001fe = 2;
+ memcpy((void*)0x20000200, "syz0\000", 5);
+ *(uint16_t*)0x20000208 = 0x24;
+ STORE_BY_BITMASK(uint16_t, , 0x2000020a, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000020b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000020b, 1, 7, 1);
+ *(uint16_t*)0x2000020c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000020e, 0x14, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000020f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000020f, 1, 7, 1);
+ *(uint16_t*)0x20000210 = 8;
+ *(uint16_t*)0x20000212 = 1;
+ *(uint32_t*)0x20000214 = htobe32(0x7f000001);
+ *(uint16_t*)0x20000218 = 0xa;
+ *(uint16_t*)0x2000021a = 0x11;
+ *(uint8_t*)0x2000021c = 0xaa;
+ *(uint8_t*)0x2000021d = 0xaa;
+ *(uint8_t*)0x2000021e = 0xaa;
+ *(uint8_t*)0x2000021f = 0xaa;
+ *(uint8_t*)0x20000220 = 0xaa;
+ *(uint8_t*)0x20000221 = 0xbb;
+ *(uint16_t*)0x20000224 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x20000226, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000227, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000227, 0, 7, 1);
+ *(uint16_t*)0x20000228 = htobe16(0x4e20);
+ *(uint16_t*)0x2000022c = 0x60;
+ STORE_BY_BITMASK(uint16_t, , 0x2000022e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000022f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000022f, 1, 7, 1);
+ *(uint16_t*)0x20000230 = 5;
+ *(uint16_t*)0x20000232 = 0x15;
+ *(uint8_t*)0x20000234 = 0x20;
+ *(uint16_t*)0x20000238 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x2000023a, 0x16, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000023b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000023b, 1, 7, 1);
+ *(uint16_t*)0x2000023c = 0x14;
+ *(uint16_t*)0x2000023e = 2;
+ *(uint64_t*)0x20000240 = htobe64(0);
+ *(uint64_t*)0x20000248 = htobe64(1);
+ *(uint16_t*)0x20000250 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000252, 0x18, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000253, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000253, 0, 7, 1);
+ *(uint64_t*)0x20000254 = htobe64(8);
+ *(uint16_t*)0x2000025c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000025e, 0xb, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000025f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000025f, 0, 7, 1);
+ *(uint32_t*)0x20000260 = htobe32(0x401);
+ *(uint16_t*)0x20000264 = 5;
+ *(uint16_t*)0x20000266 = 3;
+ *(uint8_t*)0x20000268 = 0xf7;
+ *(uint16_t*)0x2000026c = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x2000026e, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000026f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000026f, 1, 7, 1);
+ *(uint16_t*)0x20000270 = 0x14;
+ *(uint16_t*)0x20000272 = 2;
+ *(uint8_t*)0x20000274 = 0xfe;
+ *(uint8_t*)0x20000275 = 0x88;
+ *(uint8_t*)0x20000276 = 0;
+ *(uint8_t*)0x20000277 = 0;
+ *(uint8_t*)0x20000278 = 0;
+ *(uint8_t*)0x20000279 = 0;
+ *(uint8_t*)0x2000027a = 0;
+ *(uint8_t*)0x2000027b = 0;
+ *(uint8_t*)0x2000027c = 0;
+ *(uint8_t*)0x2000027d = 0;
+ *(uint8_t*)0x2000027e = 0;
+ *(uint8_t*)0x2000027f = 0;
+ *(uint8_t*)0x20000280 = 0;
+ *(uint8_t*)0x20000281 = 0;
+ *(uint8_t*)0x20000282 = 1;
+ *(uint8_t*)0x20000283 = 1;
+ *(uint16_t*)0x20000284 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000286, 0xb, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000287, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000287, 0, 7, 1);
+ *(uint32_t*)0x20000288 = htobe32(0);
+ *(uint16_t*)0x2000028c = 5;
+ *(uint16_t*)0x2000028e = 1;
+ *(uint8_t*)0x20000290 = 7;
+ *(uint16_t*)0x20000294 = 0x2c;
+ STORE_BY_BITMASK(uint16_t, , 0x20000296, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000297, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000297, 1, 7, 1);
+ *(uint16_t*)0x20000298 = 0x14;
+ *(uint16_t*)0x2000029a = 0x1a;
+ memcpy((void*)0x2000029c, "^[wlan0vboxnet0\000", 16);
+ *(uint16_t*)0x200002ac = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200002ae, 0x1c, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200002af, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200002af, 0, 7, 1);
+ *(uint32_t*)0x200002b0 = htobe32(0x7f);
+ *(uint16_t*)0x200002b4 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200002b6, 0x1b, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200002b7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200002b7, 0, 7, 1);
+ *(uint64_t*)0x200002b8 = htobe64(9);
+ *(uint16_t*)0x200002c0 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x200002c2, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200002c3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200002c3, 1, 7, 1);
+ *(uint16_t*)0x200002c4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200002c6, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200002c7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200002c7, 0, 7, 1);
+ *(uint32_t*)0x200002c8 = htobe32(9);
+ *(uint16_t*)0x200002cc = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200002ce, 0x1b, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200002cf, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200002cf, 0, 7, 1);
+ *(uint64_t*)0x200002d0 = htobe64(1);
+ *(uint16_t*)0x200002d8 = 9;
+ *(uint16_t*)0x200002da = 2;
+ memcpy((void*)0x200002dc, "syz1\000", 5);
+ *(uint64_t*)0x20000308 = 0x1a4;
+ *(uint64_t*)0x20000358 = 1;
+ *(uint64_t*)0x20000360 = 0;
+ *(uint64_t*)0x20000368 = 0;
+ *(uint32_t*)0x20000370 = 0x88000;
+ syscall(__NR_sendmsg, r[1], 0x20000340ul, 0x40000000ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/04169338416ff83f7e44c503d9cc93b31c152876.c b/syzkaller-repros/linux/04169338416ff83f7e44c503d9cc93b31c152876.c
new file mode 100644
index 0000000..d27e722
--- /dev/null
+++ b/syzkaller-repros/linux/04169338416ff83f7e44c503d9cc93b31c152876.c
@@ -0,0 +1,933 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[7] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_getsockname, -1, 0ul, 0ul);
+ res = syscall(__NR_socketpair, 1ul, 1ul, 0ul, 0x20000000ul);
+ if (res != -1)
+ r[1] = *(uint32_t*)0x20000004;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ memcpy((void*)0x20000340, "erspan0\000\000\000\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20000350 = 0;
+ res = syscall(__NR_ioctl, r[1], 0x8933ul, 0x20000340ul);
+ if (res != -1)
+ r[3] = *(uint32_t*)0x20000350;
+ syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[4] = res;
+ res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ if (res != -1)
+ r[5] = res;
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint64_t*)0x200001d0 = 0x20000180;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint64_t*)0x20000188 = 0;
+ *(uint64_t*)0x200001d8 = 1;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001f0 = 0;
+ syscall(__NR_sendmsg, r[5], 0x200001c0ul, 0ul);
+ *(uint32_t*)0x20000200 = 0x14;
+ res = syscall(__NR_getsockname, r[5], 0x20000100ul, 0x20000200ul);
+ if (res != -1)
+ r[6] = *(uint32_t*)0x20000104;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000380;
+ *(uint32_t*)0x20000380 = 0x3c;
+ *(uint16_t*)0x20000384 = 0x10;
+ *(uint16_t*)0x20000386 = 0x401;
+ *(uint32_t*)0x20000388 = 0;
+ *(uint32_t*)0x2000038c = 0;
+ *(uint8_t*)0x20000390 = 0;
+ *(uint8_t*)0x20000391 = 0;
+ *(uint16_t*)0x20000392 = 0;
+ *(uint32_t*)0x20000394 = r[6];
+ *(uint32_t*)0x20000398 = 0;
+ *(uint32_t*)0x2000039c = 0;
+ *(uint16_t*)0x200003a0 = 0x1c;
+ *(uint16_t*)0x200003a2 = 0x12;
+ *(uint16_t*)0x200003a4 = 0xc;
+ *(uint16_t*)0x200003a6 = 1;
+ memcpy((void*)0x200003a8, "bridge\000", 7);
+ *(uint16_t*)0x200003b0 = 0xc;
+ *(uint16_t*)0x200003b2 = 2;
+ *(uint16_t*)0x200003b4 = 8;
+ *(uint16_t*)0x200003b6 = 7;
+ *(uint8_t*)0x200003b8 = 5;
+ *(uint64_t*)0x200000c8 = 0x3c;
+ *(uint64_t*)0x20000198 = 1;
+ *(uint64_t*)0x200001a0 = 0;
+ *(uint64_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001b0 = 0;
+ syscall(__NR_sendmsg, r[4], 0x20000180ul, 0ul);
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0x200006c0;
+ *(uint64_t*)0x200006c0 = 0x200000c0;
+ memcpy((void*)0x200000c0,
+ "\x28\x00\x00\x00\x10\x00\x01\x04\x00\x00\x40\x00\x00\x00\x00\x00\x00"
+ "\x00\x1e\xa6",
+ 20);
+ *(uint32_t*)0x200000d4 = r[3];
+ memcpy((void*)0x200000d8, "\000\000\000\000\000\000\000\000\b\000\n\000", 12);
+ *(uint32_t*)0x200000e4 = r[6];
+ *(uint64_t*)0x200006c8 = 0x28;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmsg, r[2], 0x20000140ul, 0ul);
+ syscall(__NR_sendmsg, r[0], 0ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/048b731781ec88911e03f32b90d91298f040263d.c b/syzkaller-repros/linux/048b731781ec88911e03f32b90d91298f040263d.c
new file mode 100644
index 0000000..da9b3cc
--- /dev/null
+++ b/syzkaller-repros/linux/048b731781ec88911e03f32b90d91298f040263d.c
@@ -0,0 +1,132 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000280 = 0;
+ *(uint32_t*)0x20000288 = 8;
+ *(uint64_t*)0x20000290 = 0x20000240;
+ *(uint64_t*)0x20000240 = 0x20000100;
+ memcpy((void*)0x20000100,
+ "\x14\x00\x00\x00\x10\x00\x00\x00\x1e\x6c\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x0a\x20\x00\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00"
+ "\x00\x38\x00\x00\x00\x12\x0a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x04\x00\x04\x80\x09\x00\x02\x00\x00\x39\x7d\x00\x00"
+ "\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00"
+ "\x03\x40\x00\x00\x00\x01\x14\x00\x00\x00\x11\x00\xdf\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x0a",
+ 128);
+ *(uint64_t*)0x20000248 = 0x80;
+ *(uint64_t*)0x20000298 = 1;
+ *(uint64_t*)0x200002a0 = 0;
+ *(uint64_t*)0x200002a8 = 0;
+ *(uint32_t*)0x200002b0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000280ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0x20000100;
+ *(uint64_t*)0x20000100 = 0x20000040;
+ *(uint32_t*)0x20000040 = 0x14;
+ *(uint16_t*)0x20000044 = 0x10;
+ *(uint16_t*)0x20000046 = 1;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint8_t*)0x20000050 = 0;
+ *(uint8_t*)0x20000051 = 0;
+ *(uint16_t*)0x20000052 = htobe16(0xa);
+ *(uint32_t*)0x20000054 = 0x34;
+ *(uint8_t*)0x20000058 = 0x14;
+ *(uint8_t*)0x20000059 = 0xa;
+ *(uint16_t*)0x2000005a = 3;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint8_t*)0x20000064 = 0;
+ *(uint8_t*)0x20000065 = 0;
+ *(uint16_t*)0x20000066 = htobe16(2);
+ *(uint16_t*)0x20000068 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000006a, 3, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000006b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000006b, 0, 7, 1);
+ *(uint32_t*)0x2000006c = htobe32(1);
+ *(uint16_t*)0x20000070 = 9;
+ *(uint16_t*)0x20000072 = 1;
+ memcpy((void*)0x20000074, "syz0\000", 5);
+ *(uint16_t*)0x2000007c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000007e, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000007f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000007f, 0, 7, 1);
+ *(uint64_t*)0x20000080 = htobe64(1);
+ *(uint32_t*)0x20000088 = 0x58;
+ *(uint8_t*)0x2000008c = 2;
+ *(uint8_t*)0x2000008d = 0xa;
+ *(uint16_t*)0x2000008e = 0x603;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint8_t*)0x20000098 = 0;
+ *(uint8_t*)0x20000099 = 0;
+ *(uint16_t*)0x2000009a = htobe16(6);
+ *(uint16_t*)0x2000009c = 9;
+ *(uint16_t*)0x2000009e = 1;
+ memcpy((void*)0x200000a0, "syz1\000", 5);
+ *(uint16_t*)0x200000a8 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000aa, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000ab, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000ab, 0, 7, 1);
+ *(uint32_t*)0x200000ac = htobe32(1);
+ *(uint16_t*)0x200000b0 = 9;
+ *(uint16_t*)0x200000b2 = 1;
+ memcpy((void*)0x200000b4, "syz0\000", 5);
+ *(uint16_t*)0x200000bc = 9;
+ *(uint16_t*)0x200000be = 1;
+ memcpy((void*)0x200000c0, "syz1\000", 5);
+ *(uint16_t*)0x200000c8 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000ca, 4, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000cb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000cb, 0, 7, 1);
+ *(uint64_t*)0x200000cc = htobe64(3);
+ *(uint16_t*)0x200000d4 = 9;
+ *(uint16_t*)0x200000d6 = 1;
+ memcpy((void*)0x200000d8, "syz0\000", 5);
+ *(uint32_t*)0x200000e0 = 0x14;
+ *(uint16_t*)0x200000e4 = 0x11;
+ *(uint16_t*)0x200000e6 = 1;
+ *(uint32_t*)0x200000e8 = 0;
+ *(uint32_t*)0x200000ec = 0;
+ *(uint8_t*)0x200000f0 = 0;
+ *(uint8_t*)0x200000f1 = 0;
+ *(uint16_t*)0x200000f2 = htobe16(0xa);
+ *(uint64_t*)0x20000108 = 0xb4;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0x4000004;
+ syscall(__NR_sendmsg, r[1], 0x20000140ul, 0x42000ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/04969b1fecdf47ff3849f7fce737fd1ef12b8e4f.c b/syzkaller-repros/linux/04969b1fecdf47ff3849f7fce737fd1ef12b8e4f.c
new file mode 100644
index 0000000..dadd3dd
--- /dev/null
+++ b/syzkaller-repros/linux/04969b1fecdf47ff3849f7fce737fd1ef12b8e4f.c
@@ -0,0 +1,176 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000080;
+ *(uint32_t*)0x20000080 = 0x5c;
+ *(uint8_t*)0x20000084 = 2;
+ *(uint8_t*)0x20000085 = 6;
+ *(uint16_t*)0x20000086 = 1;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint8_t*)0x20000090 = 0;
+ *(uint8_t*)0x20000091 = 0;
+ *(uint16_t*)0x20000092 = htobe16(0);
+ *(uint16_t*)0x20000094 = 9;
+ *(uint16_t*)0x20000096 = 2;
+ memcpy((void*)0x20000098, "syz2\000", 5);
+ *(uint16_t*)0x200000a0 = 0x15;
+ *(uint16_t*)0x200000a2 = 3;
+ memcpy((void*)0x200000a4, "hash:ip,port,net\000", 17);
+ *(uint16_t*)0x200000b8 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000ba, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000bb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000bb, 1, 7, 1);
+ *(uint16_t*)0x200000bc = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000be, 0x13, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000bf, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000bf, 0, 7, 1);
+ *(uint32_t*)0x200000c0 = htobe32(0x1000);
+ *(uint16_t*)0x200000c4 = 5;
+ *(uint16_t*)0x200000c6 = 1;
+ *(uint8_t*)0x200000c8 = 7;
+ *(uint16_t*)0x200000cc = 5;
+ *(uint16_t*)0x200000ce = 4;
+ *(uint8_t*)0x200000d0 = 0;
+ *(uint16_t*)0x200000d4 = 5;
+ *(uint16_t*)0x200000d6 = 5;
+ *(uint8_t*)0x200000d8 = 2;
+ *(uint64_t*)0x200002c8 = 0x5c;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000280 = 0;
+ *(uint32_t*)0x20000288 = 0;
+ *(uint64_t*)0x20000290 = 0x20000240;
+ *(uint64_t*)0x20000240 = 0x20000180;
+ *(uint32_t*)0x20000180 = 0xb0;
+ *(uint8_t*)0x20000184 = 0xb;
+ *(uint8_t*)0x20000185 = 6;
+ *(uint16_t*)0x20000186 = 1;
+ *(uint32_t*)0x20000188 = 0x70bd27;
+ *(uint32_t*)0x2000018c = 0x25dfdbfb;
+ *(uint8_t*)0x20000190 = 0xc;
+ *(uint8_t*)0x20000191 = 0;
+ *(uint16_t*)0x20000192 = htobe16(0xa);
+ *(uint16_t*)0x20000194 = 0x14;
+ STORE_BY_BITMASK(uint16_t, , 0x20000196, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000197, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000197, 1, 7, 1);
+ *(uint16_t*)0x20000198 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x2000019a, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019b, 1, 7, 1);
+ *(uint16_t*)0x2000019c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000019e, 0x14, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019f, 1, 7, 1);
+ *(uint16_t*)0x200001a0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001a2, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 0, 7, 1);
+ *(uint32_t*)0x200001a4 = htobe32(0x7f000001);
+ *(uint16_t*)0x200001a8 = 5;
+ *(uint16_t*)0x200001aa = 1;
+ *(uint8_t*)0x200001ac = 7;
+ *(uint16_t*)0x200001b0 = 9;
+ *(uint16_t*)0x200001b2 = 2;
+ memcpy((void*)0x200001b4, "syz2\000", 5);
+ *(uint16_t*)0x200001bc = 0x50;
+ STORE_BY_BITMASK(uint16_t, , 0x200001be, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001bf, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001bf, 1, 7, 1);
+ *(uint16_t*)0x200001c0 = 0x14;
+ *(uint16_t*)0x200001c2 = 0x17;
+ memcpy((void*)0x200001c4, "rose0\000\000\000\000\000\000\000\000\000\000\000",
+ 16);
+ *(uint16_t*)0x200001d4 = 0xa;
+ *(uint16_t*)0x200001d6 = 0x11;
+ *(uint8_t*)0x200001d8 = 0xaa;
+ *(uint8_t*)0x200001d9 = 0xaa;
+ *(uint8_t*)0x200001da = 0xaa;
+ *(uint8_t*)0x200001db = 0xaa;
+ *(uint8_t*)0x200001dc = 0xaa;
+ *(uint8_t*)0x200001dd = 0x2d;
+ *(uint16_t*)0x200001e0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001e2, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001e3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001e3, 0, 7, 1);
+ *(uint32_t*)0x200001e4 = htobe32(0x6dc);
+ *(uint16_t*)0x200001e8 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ea, 0x19, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001eb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001eb, 0, 7, 1);
+ *(uint64_t*)0x200001ec = htobe64(0xc2fb);
+ *(uint16_t*)0x200001f4 = 5;
+ *(uint16_t*)0x200001f6 = 7;
+ *(uint8_t*)0x200001f8 = 0x30;
+ *(uint16_t*)0x200001fc = 5;
+ *(uint16_t*)0x200001fe = 0x15;
+ *(uint8_t*)0x20000200 = 0x3f;
+ *(uint16_t*)0x20000204 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000206, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000207, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000207, 0, 7, 1);
+ *(uint32_t*)0x20000208 = htobe32(8);
+ *(uint16_t*)0x2000020c = 9;
+ *(uint16_t*)0x2000020e = 2;
+ memcpy((void*)0x20000210, "syz2\000", 5);
+ *(uint16_t*)0x20000218 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x2000021a, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000021b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000021b, 1, 7, 1);
+ *(uint16_t*)0x2000021c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000021e, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000021f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000021f, 0, 7, 1);
+ *(uint32_t*)0x20000220 = htobe32(4);
+ *(uint16_t*)0x20000224 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000226, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000227, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000227, 1, 7, 1);
+ *(uint16_t*)0x20000228 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000022a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000022b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000022b, 0, 7, 1);
+ *(uint32_t*)0x2000022c = htobe32(0x7f000001);
+ *(uint64_t*)0x20000248 = 0xb0;
+ *(uint64_t*)0x20000298 = 1;
+ *(uint64_t*)0x200002a0 = 0;
+ *(uint64_t*)0x200002a8 = 0;
+ *(uint32_t*)0x200002b0 = 0x8000;
+ syscall(__NR_sendmsg, r[1], 0x20000280ul, 0xc0000c4ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/05505cdef9d15919d3ef0128391540db21272c98.c b/syzkaller-repros/linux/05505cdef9d15919d3ef0128391540db21272c98.c
new file mode 100644
index 0000000..c4dbf7b
--- /dev/null
+++ b/syzkaller-repros/linux/05505cdef9d15919d3ef0128391540db21272c98.c
@@ -0,0 +1,386 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 1;
+ *(uint32_t*)0x2000000c = 3;
+ *(uint32_t*)0x20000010 = 0x100;
+ *(uint64_t*)0x20000018 = 0x200003c0;
+ memcpy(
+ (void*)0x200003c0,
+ "\xcb\xb6\x2c\x7c\x7e\x12\x72\x7d\x60\xc5\xdb\x26\x5c\x1d\x8b\x3f\x75\x25"
+ "\x50\xd4\xea\xc7\xaf\xf1\x02\x13\x26\xe1\x5d\xfd\xad\x91\x1d\x57\xa8\x53"
+ "\x41\x4b\x19\x47\x02\xa4\x1a\x75\x60\x56\x8b\xe1\x11\x1d\xac\x9f\xf2\x58"
+ "\x6d\x67\xdc\x8e\xf3\xe9\xd3\x66\x94\xc5\xea\x96\xd8\x98\x5a\x99\x53\xe8"
+ "\x77\x5c\xbf\x7a\xe1\x51\xea\x1f\xd6\x1f\xbc\x2d\x44\xe7\x60\x31\x83\x3d"
+ "\xff\xb4\x47\xc4\x25\xc9\x74\x9c\x7d\xe7\xfb\xe2\xe5\x65\xb4\xa2\x5f\x7b"
+ "\x2a\xc0\x13\x92\xce\x04\xec\x8d\x6d\x21\x0e\x0a\x23\xae\x3a\x5f\xd8\x1c"
+ "\x3c\x89\xc9\x28\x74\x70\x9f\xcd\xd4\xd4\xc3\xff\xe7\xfa\x05\x2a\xc6\x8f"
+ "\xb6\xdf\x7e\x48\x2e\x24\xbe\x6a\xc8\x19\x10\x39\xb4\x34\xaa\x0e\x9f\x97"
+ "\x39\xae\xdf\x30\xc0\xfa\x9c\x42\xcd\xa4\x11\x02\x5c\xa2\x0c\x42\xbf\x88"
+ "\x68\x56\x03\x99\x87\x3f\x4d\x1b\x28\xed\x71\x3e\x41\x1b\x34\xec\x02\x63"
+ "\x21\xc8\xcd\x9a\xd1\x7c\xbc\x95\x70\x4c\x14\x2d\x7c\x71\x06\x3b\x4a\x0b"
+ "\x52\xe2\x20\x73\xf8\x59\xd6\x32\x89\x92\x12\x6e\x5f\x50\x57\xad\x1d\x02"
+ "\x29\xba\xde\xc1\xe0\x88\x0f\x47\x6f\x18\xce\x68\x55\x60\x78\xa0\x06\x7d"
+ "\x8e\x90\x05\x7f\x56\x0b\x51\x51\xc4\x50\xe6\x55\x89\x81\x2f\x77\x9b\x50"
+ "\xe4\xde\xd6\x60\xee\x4a\xa6\x1e\x7f\x84\xa9\xb4\xb7\x91\x83\x71\x14\x09"
+ "\x55\x39\xfb\x55\x73\xe4\x7c\xce\x26\xdc\x38\x31\x19\x13\x99\x51\x81\xe7"
+ "\x28\xfd\x4d\x6d\x33\x4e\x62\xfd\x0a\x82\x2f\x93\x71\xbc\xdc\x43\xc8\xa6"
+ "\x96\x88\xa1\x1f\xc9\xf4\x3a\xfe\x64\x2c\x30\xdd\xf3\x94\x65\xb1\x3c\xf1"
+ "\xdd\xad\xd7\x89\x70\x77\x18\x27\xf4\x45\xf0\xd4\x56\x1e\x8e\x2b\xb6\xcf"
+ "\x22\x44\x63\x4b\xcd\x72\xd1\x24\xf3\xca\xa1\x52\xc6\xfd\x6d\x47\xbb\x00"
+ "\x4b\x97\x97\x5d\x4a\x46\xb2\xee\x12\x9b\x88\x9d\xc5\x9c\x1c\x71\x62\xff"
+ "\xf2\x2c\x42\x95\x54\x52\x95\xea\x72\xfe\x14\xc6\xb2\xba\xb3\x5a\xb5\x45"
+ "\x51\x73\x98\xb0\x03\xb6\xd3\xb8\x9c\x5c\x64\xb4\x49\xf7\xd5\x60\xdd\xe2"
+ "\x0f\xc1\x3b\x3e\xc8\x8d\xc0\x52\x42\xa1\x60\x07\x6c\xcb\xff\x3e\x32\xb8"
+ "\x78\x0b\xd1\x91\xa0\xb1\x2a\x6f\x99\x00\xa9\x3f\xa1\x2d\x9f\xb5\xed\x34"
+ "\x88\xd5\xcd\x0a\xa3\x29\x58\x3f\x2c\x47\xc4\xfd\x47\x26\x46\x9c\x98\xe0"
+ "\xb6\x6d\x74\xc3\x1d\x0a\x1f\x7f\xc1\x0c\xc1\x94\x4d\x25\x26\x7e\xff\x7a"
+ "\x74\x0c\xc4\x30\x06\x9b\x58\x47\x9c\xa6\x96\x00\x63\x6a\x0f\x22\xa4\x70"
+ "\xa6\x9b\x46\xc1\xcc\x1b\x95\xcf\x32\xdd\x7b\x73\xad\x67\x41\x61\xca\x39"
+ "\x25\x83\xaa\x83\x4a\xaa\xde\x88\xa4\x39\x33\x89\xb7\x6d\x58\x8a\x60\x81"
+ "\x91\xdb\x7c\xa7\x5d\xd0\x09\x38\x2a\x45\x83\xe8\x78\x1e\xb0\x9f\x48\xa4"
+ "\x4d\x06\xb4\x17\x56\xeb\x3f\x1b\x7e\xea\x18\xad\xf2\x97\x83\x22\xd0\xb3"
+ "\x84\xdf\x03\x07\x98\x91\xe1\x0f\x09\x2c\x57\x33\x20\xfb\x94\x1f\x10\xe3"
+ "\xc3\xaf\x6f\x3e\x72\xb2\xaf\xcd\x95\xa3\x66\x6a\x6a\x40\xa8\x40\xe6\x3d"
+ "\x1c\xb9\xe2\x49\x25\xc0\x49\x7a\x04\xef\x7b\x9b\x1e\xe3\x9d\xe0\x45\x6f"
+ "\xec\xd6\x76\xac\xee\x23\x3f\x5b\x64\x5e\x8d\x05\xf3\xf5\x05\xa1\x2a\x0f"
+ "\x5b\x35\x65\x86\xf2\x2c\x2c\x2c\xeb\xef\x83\xc5\xe6\x8c\x22\x72\x34\x95"
+ "\xab\xa0\x64\x27\x92\x55\xde\x48\x9e\x33\xe9\x20\x9a\x63\x68\x90\xbc\xfb"
+ "\x2a\x52\x7e\x8d\xa8\x36\x21\xae\xf3\x74\xf5\xa1\x1d\x8a\xc7\x7f\x5d\xcd"
+ "\x42\x1f\x45\xe5\x2d\xdf\x9b\xc3\x5f\x64\xcf\x72\x1c\xe6\xc9\x6b\x56\x13"
+ "\x26\x8c\x02\x5c\xa9\x91\x0a\x8a\x23\x5e\x6a\xf3\xd6\x7a\xdd\xc6\x6e\x75"
+ "\xc1\x56\x4a\x7f\x86\x84\xfc\xd2\x3e\xc9\x8d\x61\xa4\xfa\x42\x2c\x55\xe6"
+ "\x78\x9c\xbc\x42\xb1\xd5\x32\x63\x3e\x65\x8a\x5c\x2f\xfe\x57\x67\x03\x97"
+ "\x62\xf1\x8c\xce\x89\xb8\x00\x0e\x37\xca\xbc\x35\x40\x9d\x3c\x7a\x02\x13"
+ "\xde\x87\xce\x95\xcf\xbf\xb0\xc7\x1b\xe4\xc4\xef\x44\x86\x6b\xd8\xe0\x50"
+ "\xe3\x36\xb3\x1a\x6e\x8f\x15\xbd\x21\x60\xe5\x48\x48\xad\xa2\x56\xdf\x90"
+ "\x27\x58\xeb\xbc\x1e\x83\x7f\xab\x4c\xb8\xbb\x84\x67\xa7\x3d\xf7\x17\xd9"
+ "\x2e\x22\x04\x48\x2f\xe9\x5c\x21\x12\x11\x86\xa5\x7c\x3b\x12\xf7\x5c\x83"
+ "\x6a\xb7\x02\x43\x34\x18\xf3\x29\x44\x32\x3e\xaa\xad\xbc\xa3\x66\x96\x1c"
+ "\x25\x62\x0c\x43\x95\x1a\x7a\x3f\xd3\xe3\xcc\x85\xd6\xa3\x99\x6b\x50\xd1"
+ "\x2e\xa7\x6d\xf6\x58\xa6\x40\x5f\xdf\x1c\x9f\x2c\x05\x24\x8d\x95\x15\xce"
+ "\x96\x65\x0e\xbf\x62\x96\x64\xe6\xc1\x92\xdd\x28\xe1\x61\x72\xbe\x15\x93"
+ "\xe9\x4d\xbc\xa0\xe5\x54\xfc\xe9\x73\x6c\x73\x54\x03\x0c\x64\xfd\xaf\x35"
+ "\x03\x8e\x1f\x1e\x1d\x20\xe0\x6f\x34\x8e\xf5\xae\x75\x41\x39\xb4\xe8\x12"
+ "\xc6\x0f\xbc\x55\xba\xce\x83\xf2\x7b\xb8\x35\xc1\x64\xc2\x9f\x5f\x7c\x1d"
+ "\xbe\xeb\xfd\x98\x8a\x16\x23\x5c\x4b\xbe\xe4\xd9\xa3\xbc\x66\x6f",
+ 1024);
+ syscall(__NR_ioctl, r[0], 0x4b72ul, 0x20000000ul);
+ res = syz_open_dev(0xc, 4, 0x15);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x20000000 = 0;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint16_t*)0x20000004 = 0;
+ *(uint16_t*)0x20000006 = 5;
+ *(uint16_t*)0x20000008 = 5;
+ *(uint16_t*)0x2000000a = 0;
+ syscall(__NR_ioctl, r[1], 0x560aul, 0x20000000ul);
+ syscall(__NR_ioctl, r[1], 0x4b48ul, 0ul);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0x67514c7366170adeul,
+ 0ul);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_write, r[2], 0ul, 0ul);
+ syscall(__NR_ioctl, -1, 0x460ful, 0ul);
+ syscall(__NR_mmap, 0x20000000ul, 0x3000ul, 0x2000002ul, 0x11ul, -1, 0ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[3] = res;
+ memcpy((void*)0x20000100, "\xe0\x9b\x3d", 3);
+ syscall(__NR_write, r[3], 0x20000100ul, 0x567ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/063f4f68ef32f5cae06ea84e5fb8d58f2dacab2a.c b/syzkaller-repros/linux/063f4f68ef32f5cae06ea84e5fb8d58f2dacab2a.c
new file mode 100644
index 0000000..8b73232
--- /dev/null
+++ b/syzkaller-repros/linux/063f4f68ef32f5cae06ea84e5fb8d58f2dacab2a.c
@@ -0,0 +1,795 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000880,
+ "filter\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000",
+ 32);
+ *(uint32_t*)0x200008a0 = 4;
+ *(uint32_t*)0x200008a4 = 4;
+ *(uint32_t*)0x200008a8 = 0x3c8;
+ *(uint32_t*)0x200008ac = 0;
+ *(uint32_t*)0x200008b0 = 0;
+ *(uint32_t*)0x200008b4 = 0;
+ *(uint32_t*)0x200008b8 = 0x2e0;
+ *(uint32_t*)0x200008bc = 0x2e0;
+ *(uint32_t*)0x200008c0 = 0x2e0;
+ *(uint32_t*)0x200008c4 = 4;
+ *(uint64_t*)0x200008c8 = 0;
+ *(uint8_t*)0x200008d0 = 0;
+ *(uint8_t*)0x200008d1 = 0;
+ *(uint8_t*)0x200008d2 = 0;
+ *(uint8_t*)0x200008d3 = 0;
+ *(uint8_t*)0x200008d4 = 0;
+ *(uint8_t*)0x200008d5 = 0;
+ *(uint8_t*)0x200008d6 = 0;
+ *(uint8_t*)0x200008d7 = 0;
+ *(uint8_t*)0x200008d8 = 0;
+ *(uint8_t*)0x200008d9 = 0;
+ *(uint8_t*)0x200008da = 0;
+ *(uint8_t*)0x200008db = 0;
+ *(uint8_t*)0x200008dc = 0;
+ *(uint8_t*)0x200008dd = 0;
+ *(uint8_t*)0x200008de = 0;
+ *(uint8_t*)0x200008df = 0;
+ *(uint8_t*)0x200008e0 = 0;
+ *(uint8_t*)0x200008e1 = 0;
+ *(uint8_t*)0x200008e2 = 0;
+ *(uint8_t*)0x200008e3 = 0;
+ *(uint8_t*)0x200008e4 = 0;
+ *(uint8_t*)0x200008e5 = 0;
+ *(uint8_t*)0x200008e6 = 0;
+ *(uint8_t*)0x200008e7 = 0;
+ *(uint8_t*)0x200008e8 = 0;
+ *(uint8_t*)0x200008e9 = 0;
+ *(uint8_t*)0x200008ea = 0;
+ *(uint8_t*)0x200008eb = 0;
+ *(uint8_t*)0x200008ec = 0;
+ *(uint8_t*)0x200008ed = 0;
+ *(uint8_t*)0x200008ee = 0;
+ *(uint8_t*)0x200008ef = 0;
+ *(uint8_t*)0x200008f0 = 0;
+ *(uint8_t*)0x200008f1 = 0;
+ *(uint8_t*)0x200008f2 = 0;
+ *(uint8_t*)0x200008f3 = 0;
+ *(uint8_t*)0x200008f4 = 0;
+ *(uint8_t*)0x200008f5 = 0;
+ *(uint8_t*)0x200008f6 = 0;
+ *(uint8_t*)0x200008f7 = 0;
+ *(uint8_t*)0x200008f8 = 0;
+ *(uint8_t*)0x200008f9 = 0;
+ *(uint8_t*)0x200008fa = 0;
+ *(uint8_t*)0x200008fb = 0;
+ *(uint8_t*)0x200008fc = 0;
+ *(uint8_t*)0x200008fd = 0;
+ *(uint8_t*)0x200008fe = 0;
+ *(uint8_t*)0x200008ff = 0;
+ *(uint8_t*)0x20000900 = 0;
+ *(uint8_t*)0x20000901 = 0;
+ *(uint8_t*)0x20000902 = 0;
+ *(uint8_t*)0x20000903 = 0;
+ *(uint8_t*)0x20000904 = 0;
+ *(uint8_t*)0x20000905 = 0;
+ *(uint8_t*)0x20000906 = 0;
+ *(uint8_t*)0x20000907 = 0;
+ *(uint8_t*)0x20000908 = 0;
+ *(uint8_t*)0x20000909 = 0;
+ *(uint8_t*)0x2000090a = 0;
+ *(uint8_t*)0x2000090b = 0;
+ *(uint8_t*)0x2000090c = 0;
+ *(uint8_t*)0x2000090d = 0;
+ *(uint8_t*)0x2000090e = 0;
+ *(uint8_t*)0x2000090f = 0;
+ *(uint8_t*)0x20000910 = 0;
+ *(uint8_t*)0x20000911 = 0;
+ *(uint8_t*)0x20000912 = 0;
+ *(uint8_t*)0x20000913 = 0;
+ *(uint8_t*)0x20000914 = 0;
+ *(uint8_t*)0x20000915 = 0;
+ *(uint8_t*)0x20000916 = 0;
+ *(uint8_t*)0x20000917 = 0;
+ *(uint8_t*)0x20000918 = 0;
+ *(uint8_t*)0x20000919 = 0;
+ *(uint8_t*)0x2000091a = 0;
+ *(uint8_t*)0x2000091b = 0;
+ *(uint8_t*)0x2000091c = 0;
+ *(uint8_t*)0x2000091d = 0;
+ *(uint8_t*)0x2000091e = 0;
+ *(uint8_t*)0x2000091f = 0;
+ *(uint8_t*)0x20000920 = 0;
+ *(uint8_t*)0x20000921 = 0;
+ *(uint8_t*)0x20000922 = 0;
+ *(uint8_t*)0x20000923 = 0;
+ *(uint8_t*)0x20000924 = 0;
+ *(uint8_t*)0x20000925 = 0;
+ *(uint8_t*)0x20000926 = 0;
+ *(uint8_t*)0x20000927 = 0;
+ *(uint8_t*)0x20000928 = 0;
+ *(uint8_t*)0x20000929 = 0;
+ *(uint8_t*)0x2000092a = 0;
+ *(uint8_t*)0x2000092b = 0;
+ *(uint8_t*)0x2000092c = 0;
+ *(uint8_t*)0x2000092d = 0;
+ *(uint8_t*)0x2000092e = 0;
+ *(uint8_t*)0x2000092f = 0;
+ *(uint8_t*)0x20000930 = 0;
+ *(uint8_t*)0x20000931 = 0;
+ *(uint8_t*)0x20000932 = 0;
+ *(uint8_t*)0x20000933 = 0;
+ *(uint8_t*)0x20000934 = 0;
+ *(uint8_t*)0x20000935 = 0;
+ *(uint8_t*)0x20000936 = 0;
+ *(uint8_t*)0x20000937 = 0;
+ *(uint8_t*)0x20000938 = 0;
+ *(uint8_t*)0x20000939 = 0;
+ *(uint8_t*)0x2000093a = 0;
+ *(uint8_t*)0x2000093b = 0;
+ *(uint8_t*)0x2000093c = 0;
+ *(uint8_t*)0x2000093d = 0;
+ *(uint8_t*)0x2000093e = 0;
+ *(uint8_t*)0x2000093f = 0;
+ *(uint8_t*)0x20000940 = 0;
+ *(uint8_t*)0x20000941 = 0;
+ *(uint8_t*)0x20000942 = 0;
+ *(uint8_t*)0x20000943 = 0;
+ *(uint8_t*)0x20000944 = 0;
+ *(uint8_t*)0x20000945 = 0;
+ *(uint8_t*)0x20000946 = 0;
+ *(uint8_t*)0x20000947 = 0;
+ *(uint8_t*)0x20000948 = 0;
+ *(uint8_t*)0x20000949 = 0;
+ *(uint8_t*)0x2000094a = 0;
+ *(uint8_t*)0x2000094b = 0;
+ *(uint8_t*)0x2000094c = 0;
+ *(uint8_t*)0x2000094d = 0;
+ *(uint8_t*)0x2000094e = 0;
+ *(uint8_t*)0x2000094f = 0;
+ *(uint8_t*)0x20000950 = 0;
+ *(uint8_t*)0x20000951 = 0;
+ *(uint8_t*)0x20000952 = 0;
+ *(uint8_t*)0x20000953 = 0;
+ *(uint8_t*)0x20000954 = 0;
+ *(uint8_t*)0x20000955 = 0;
+ *(uint8_t*)0x20000956 = 0;
+ *(uint8_t*)0x20000957 = 0;
+ *(uint8_t*)0x20000958 = 0;
+ *(uint8_t*)0x20000959 = 0;
+ *(uint8_t*)0x2000095a = 0;
+ *(uint8_t*)0x2000095b = 0;
+ *(uint8_t*)0x2000095c = 0;
+ *(uint8_t*)0x2000095d = 0;
+ *(uint8_t*)0x2000095e = 0;
+ *(uint8_t*)0x2000095f = 0;
+ *(uint8_t*)0x20000960 = 0;
+ *(uint8_t*)0x20000961 = 0;
+ *(uint8_t*)0x20000962 = 0;
+ *(uint8_t*)0x20000963 = 0;
+ *(uint8_t*)0x20000964 = 0;
+ *(uint8_t*)0x20000965 = 0;
+ *(uint8_t*)0x20000966 = 0;
+ *(uint8_t*)0x20000967 = 0;
+ *(uint8_t*)0x20000968 = 0;
+ *(uint8_t*)0x20000969 = 0;
+ *(uint8_t*)0x2000096a = 0;
+ *(uint8_t*)0x2000096b = 0;
+ *(uint8_t*)0x2000096c = 0;
+ *(uint8_t*)0x2000096d = 0;
+ *(uint8_t*)0x2000096e = 0;
+ *(uint8_t*)0x2000096f = 0;
+ *(uint8_t*)0x20000970 = 0;
+ *(uint8_t*)0x20000971 = 0;
+ *(uint8_t*)0x20000972 = 0;
+ *(uint8_t*)0x20000973 = 0;
+ *(uint16_t*)0x20000974 = 0xc0;
+ *(uint16_t*)0x20000976 = 0xf0;
+ *(uint32_t*)0x20000978 = 0;
+ *(uint64_t*)0x20000980 = 0;
+ *(uint64_t*)0x20000988 = 0;
+ *(uint16_t*)0x20000990 = 0x30;
+ memcpy((void*)0x20000992,
+ "CONNMARK\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000",
+ 29);
+ *(uint8_t*)0x200009af = 1;
+ *(uint32_t*)0x200009b0 = 0x80000000;
+ *(uint32_t*)0x200009b4 = 0x20;
+ *(uint32_t*)0x200009b8 = 0x80004;
+ *(uint8_t*)0x200009bc = 0;
+ *(uint32_t*)0x200009c0 = htobe32(0x7f000001);
+ *(uint8_t*)0x200009c4 = 0xac;
+ *(uint8_t*)0x200009c5 = 0x1e;
+ *(uint8_t*)0x200009c6 = 0;
+ *(uint8_t*)0x200009c7 = 1;
+ *(uint32_t*)0x200009c8 = htobe32(0);
+ *(uint32_t*)0x200009cc = htobe32(0);
+ *(uint8_t*)0x200009d0 = 0;
+ *(uint8_t*)0x200009d1 = 7;
+ *(uint8_t*)0x200009d2 = 0;
+ *(uint8_t*)0x200009d3 = 0;
+ *(uint8_t*)0x200009d4 = 0;
+ *(uint8_t*)0x200009d5 = 0;
+ *(uint8_t*)0x200009d6 = 0;
+ *(uint8_t*)0x200009d7 = 0;
+ *(uint8_t*)0x200009d8 = 0;
+ *(uint8_t*)0x200009d9 = 0;
+ *(uint8_t*)0x200009da = 0;
+ *(uint8_t*)0x200009db = 0;
+ *(uint8_t*)0x200009dc = 0;
+ *(uint8_t*)0x200009dd = 0;
+ *(uint8_t*)0x200009de = 0;
+ *(uint8_t*)0x200009df = 0;
+ *(uint8_t*)0x200009e0 = 0;
+ *(uint8_t*)0x200009e1 = 0;
+ *(uint8_t*)0x200009e2 = 0;
+ *(uint8_t*)0x200009e3 = 0;
+ *(uint8_t*)0x200009e4 = 0;
+ *(uint8_t*)0x200009e5 = 0;
+ *(uint8_t*)0x200009e6 = 0;
+ *(uint8_t*)0x200009e7 = 0;
+ *(uint8_t*)0x200009f2 = 0;
+ *(uint8_t*)0x200009f3 = 0;
+ *(uint8_t*)0x200009f4 = 0;
+ *(uint8_t*)0x200009f5 = 0;
+ *(uint8_t*)0x200009f6 = 0;
+ *(uint8_t*)0x200009f7 = 0;
+ *(uint8_t*)0x200009f8 = 0;
+ *(uint8_t*)0x200009f9 = 0;
+ *(uint8_t*)0x200009fa = 0;
+ *(uint8_t*)0x200009fb = 0;
+ *(uint8_t*)0x200009fc = 0;
+ *(uint8_t*)0x200009fd = 0;
+ *(uint8_t*)0x200009fe = 0;
+ *(uint8_t*)0x200009ff = 0;
+ *(uint8_t*)0x20000a00 = 0;
+ *(uint8_t*)0x20000a01 = 0;
+ *(uint8_t*)0x20000a02 = 0;
+ *(uint8_t*)0x20000a03 = 0;
+ *(uint8_t*)0x20000a04 = 0;
+ *(uint8_t*)0x20000a05 = 0;
+ *(uint8_t*)0x20000a06 = 0;
+ *(uint8_t*)0x20000a07 = 0;
+ *(uint16_t*)0x20000a12 = htobe16(0);
+ *(uint16_t*)0x20000a14 = htobe16(0);
+ *(uint16_t*)0x20000a16 = htobe16(0);
+ *(uint16_t*)0x20000a18 = htobe16(0);
+ *(uint16_t*)0x20000a1a = htobe16(0);
+ *(uint16_t*)0x20000a1c = htobe16(0);
+ memcpy((void*)0x20000a1e,
+ "yam\371\377\377\377\000\000\000\000\000\000\000\000\000", 16);
+ memcpy((void*)0x20000a2e,
+ "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint8_t*)0x20000a3e = 0;
+ *(uint8_t*)0x20000a4e = 0;
+ *(uint8_t*)0x20000a5e = 0;
+ *(uint16_t*)0x20000a60 = 0;
+ *(uint16_t*)0x20000a64 = 0xc0;
+ *(uint16_t*)0x20000a66 = 0xe8;
+ *(uint32_t*)0x20000a68 = 0;
+ *(uint64_t*)0x20000a70 = 0;
+ *(uint64_t*)0x20000a78 = 0;
+ *(uint16_t*)0x20000a80 = 0x28;
+ memcpy((void*)0x20000a82,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000",
+ 29);
+ *(uint8_t*)0x20000a9f = 0;
+ *(uint32_t*)0x20000aa0 = 0xfffffffe;
+ *(uint32_t*)0x20000aa8 = htobe32(0xe0000002);
+ *(uint32_t*)0x20000aac = htobe32(0x7f000001);
+ *(uint32_t*)0x20000ab0 = htobe32(0);
+ *(uint32_t*)0x20000ab4 = htobe32(0);
+ *(uint8_t*)0x20000ab8 = 0;
+ *(uint8_t*)0x20000ab9 = 0;
+ *(uint8_t*)0x20000aba = 0;
+ *(uint8_t*)0x20000abb = 0;
+ *(uint8_t*)0x20000abc = 0;
+ *(uint8_t*)0x20000abd = 0;
+ *(uint8_t*)0x20000abe = 0;
+ *(uint8_t*)0x20000abf = 0;
+ *(uint8_t*)0x20000ac0 = 0;
+ *(uint8_t*)0x20000ac1 = 0;
+ *(uint8_t*)0x20000ac2 = 0;
+ *(uint8_t*)0x20000ac3 = 0;
+ *(uint8_t*)0x20000ac4 = 0;
+ *(uint8_t*)0x20000ac5 = 0;
+ *(uint8_t*)0x20000ac6 = 0;
+ *(uint8_t*)0x20000ac7 = 0;
+ *(uint8_t*)0x20000ac8 = 0;
+ *(uint8_t*)0x20000ac9 = 0;
+ *(uint8_t*)0x20000aca = 0;
+ *(uint8_t*)0x20000acb = 0;
+ *(uint8_t*)0x20000acc = 0;
+ *(uint8_t*)0x20000acd = 0;
+ *(uint8_t*)0x20000ace = 0;
+ *(uint8_t*)0x20000acf = -1;
+ *(uint8_t*)0x20000ada = 1;
+ *(uint8_t*)0x20000adb = 0x80;
+ *(uint8_t*)0x20000adc = 0xc2;
+ *(uint8_t*)0x20000add = 0;
+ *(uint8_t*)0x20000ade = 0;
+ *(uint8_t*)0x20000adf = 0;
+ *(uint8_t*)0x20000aea = 0;
+ *(uint8_t*)0x20000aeb = 0;
+ *(uint8_t*)0x20000aec = 0;
+ *(uint8_t*)0x20000aed = 0;
+ *(uint8_t*)0x20000aee = 0;
+ *(uint8_t*)0x20000aef = 0;
+ *(uint16_t*)0x20000afa = htobe16(0);
+ *(uint16_t*)0x20000afc = htobe16(0);
+ *(uint16_t*)0x20000afe = htobe16(0);
+ *(uint16_t*)0x20000b00 = htobe16(0);
+ *(uint16_t*)0x20000b02 = htobe16(0);
+ *(uint16_t*)0x20000b04 = htobe16(0x94);
+ memcpy((void*)0x20000b06, "team0\000\000\000\000\000\000\000\000\000\000\000",
+ 16);
+ memcpy((void*)0x20000b16, "syzkaller0\000\000\000\000\000\000", 16);
+ *(uint8_t*)0x20000b26 = 0;
+ *(uint8_t*)0x20000b36 = 0;
+ *(uint8_t*)0x20000b46 = 0;
+ *(uint16_t*)0x20000b48 = 0;
+ *(uint16_t*)0x20000b4c = 0xc0;
+ *(uint16_t*)0x20000b4e = 0x108;
+ *(uint32_t*)0x20000b50 = 0;
+ *(uint64_t*)0x20000b58 = 0;
+ *(uint64_t*)0x20000b60 = 0;
+ *(uint16_t*)0x20000b68 = 0x48;
+ memcpy((void*)0x20000b6a,
+ "IDLETIMER\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000",
+ 29);
+ *(uint8_t*)0x20000b87 = 0;
+ *(uint32_t*)0x20000b88 = 5;
+ memcpy((void*)0x20000b8c,
+ "syz0\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000",
+ 28);
+ *(uint64_t*)0x20000ba8 = 0;
+ *(uint8_t*)0x20000bb0 = 0;
+ *(uint8_t*)0x20000bb1 = 0;
+ *(uint8_t*)0x20000bb2 = 0;
+ *(uint8_t*)0x20000bb3 = 0;
+ *(uint8_t*)0x20000bb4 = 0;
+ *(uint8_t*)0x20000bb5 = 0;
+ *(uint8_t*)0x20000bb6 = 0;
+ *(uint8_t*)0x20000bb7 = 0;
+ *(uint8_t*)0x20000bb8 = 0;
+ *(uint8_t*)0x20000bb9 = 0;
+ *(uint8_t*)0x20000bba = 0;
+ *(uint8_t*)0x20000bbb = 0;
+ *(uint8_t*)0x20000bbc = 0;
+ *(uint8_t*)0x20000bbd = 0;
+ *(uint8_t*)0x20000bbe = 0;
+ *(uint8_t*)0x20000bbf = 0;
+ *(uint8_t*)0x20000bc0 = 0;
+ *(uint8_t*)0x20000bc1 = 0;
+ *(uint8_t*)0x20000bc2 = 0;
+ *(uint8_t*)0x20000bc3 = 0;
+ *(uint8_t*)0x20000bc4 = 0;
+ *(uint8_t*)0x20000bc5 = 0;
+ *(uint8_t*)0x20000bc6 = 0;
+ *(uint8_t*)0x20000bc7 = 0;
+ *(uint8_t*)0x20000bc8 = 0;
+ *(uint8_t*)0x20000bc9 = 0;
+ *(uint8_t*)0x20000bca = 0;
+ *(uint8_t*)0x20000bcb = 0;
+ *(uint8_t*)0x20000bcc = 0;
+ *(uint8_t*)0x20000bcd = 0;
+ *(uint8_t*)0x20000bce = 0;
+ *(uint8_t*)0x20000bcf = 0;
+ *(uint8_t*)0x20000bd0 = 0;
+ *(uint8_t*)0x20000bd1 = 0;
+ *(uint8_t*)0x20000bd2 = 0;
+ *(uint8_t*)0x20000bd3 = 0;
+ *(uint8_t*)0x20000bd4 = 0;
+ *(uint8_t*)0x20000bd5 = 0;
+ *(uint8_t*)0x20000bd6 = 0;
+ *(uint8_t*)0x20000bd7 = 0;
+ *(uint8_t*)0x20000bd8 = 0;
+ *(uint8_t*)0x20000bd9 = 0;
+ *(uint8_t*)0x20000bda = 0;
+ *(uint8_t*)0x20000bdb = 0;
+ *(uint8_t*)0x20000bdc = 0;
+ *(uint8_t*)0x20000bdd = 0;
+ *(uint8_t*)0x20000bde = 0;
+ *(uint8_t*)0x20000bdf = 0;
+ *(uint8_t*)0x20000be0 = 0;
+ *(uint8_t*)0x20000be1 = 0;
+ *(uint8_t*)0x20000be2 = 0;
+ *(uint8_t*)0x20000be3 = 0;
+ *(uint8_t*)0x20000be4 = 0;
+ *(uint8_t*)0x20000be5 = 0;
+ *(uint8_t*)0x20000be6 = 0;
+ *(uint8_t*)0x20000be7 = 0;
+ *(uint8_t*)0x20000be8 = 0;
+ *(uint8_t*)0x20000be9 = 0;
+ *(uint8_t*)0x20000bea = 0;
+ *(uint8_t*)0x20000beb = 0;
+ *(uint8_t*)0x20000bec = 0;
+ *(uint8_t*)0x20000bed = 0;
+ *(uint8_t*)0x20000bee = 0;
+ *(uint8_t*)0x20000bef = 0;
+ *(uint8_t*)0x20000bf0 = 0;
+ *(uint8_t*)0x20000bf1 = 0;
+ *(uint8_t*)0x20000bf2 = 0;
+ *(uint8_t*)0x20000bf3 = 0;
+ *(uint8_t*)0x20000bf4 = 0;
+ *(uint8_t*)0x20000bf5 = 0;
+ *(uint8_t*)0x20000bf6 = 0;
+ *(uint8_t*)0x20000bf7 = 0;
+ *(uint8_t*)0x20000bf8 = 0;
+ *(uint8_t*)0x20000bf9 = 0;
+ *(uint8_t*)0x20000bfa = 0;
+ *(uint8_t*)0x20000bfb = 0;
+ *(uint8_t*)0x20000bfc = 0;
+ *(uint8_t*)0x20000bfd = 0;
+ *(uint8_t*)0x20000bfe = 0;
+ *(uint8_t*)0x20000bff = 0;
+ *(uint8_t*)0x20000c00 = 0;
+ *(uint8_t*)0x20000c01 = 0;
+ *(uint8_t*)0x20000c02 = 0;
+ *(uint8_t*)0x20000c03 = 0;
+ *(uint8_t*)0x20000c04 = 0;
+ *(uint8_t*)0x20000c05 = 0;
+ *(uint8_t*)0x20000c06 = 0;
+ *(uint8_t*)0x20000c07 = 0;
+ *(uint8_t*)0x20000c08 = 0;
+ *(uint8_t*)0x20000c09 = 0;
+ *(uint8_t*)0x20000c0a = 0;
+ *(uint8_t*)0x20000c0b = 0;
+ *(uint8_t*)0x20000c0c = 0;
+ *(uint8_t*)0x20000c0d = 0;
+ *(uint8_t*)0x20000c0e = 0;
+ *(uint8_t*)0x20000c0f = 0;
+ *(uint8_t*)0x20000c10 = 0;
+ *(uint8_t*)0x20000c11 = 0;
+ *(uint8_t*)0x20000c12 = 0;
+ *(uint8_t*)0x20000c13 = 0;
+ *(uint8_t*)0x20000c14 = 0;
+ *(uint8_t*)0x20000c15 = 0;
+ *(uint8_t*)0x20000c16 = 0;
+ *(uint8_t*)0x20000c17 = 0;
+ *(uint8_t*)0x20000c18 = 0;
+ *(uint8_t*)0x20000c19 = 0;
+ *(uint8_t*)0x20000c1a = 0;
+ *(uint8_t*)0x20000c1b = 0;
+ *(uint8_t*)0x20000c1c = 0;
+ *(uint8_t*)0x20000c1d = 0;
+ *(uint8_t*)0x20000c1e = 0;
+ *(uint8_t*)0x20000c1f = 0;
+ *(uint8_t*)0x20000c20 = 0;
+ *(uint8_t*)0x20000c21 = 0;
+ *(uint8_t*)0x20000c22 = 0;
+ *(uint8_t*)0x20000c23 = 0;
+ *(uint8_t*)0x20000c24 = 0;
+ *(uint8_t*)0x20000c25 = 0;
+ *(uint8_t*)0x20000c26 = 0;
+ *(uint8_t*)0x20000c27 = 0;
+ *(uint8_t*)0x20000c28 = 0;
+ *(uint8_t*)0x20000c29 = 0;
+ *(uint8_t*)0x20000c2a = 0;
+ *(uint8_t*)0x20000c2b = 0;
+ *(uint8_t*)0x20000c2c = 0;
+ *(uint8_t*)0x20000c2d = 0;
+ *(uint8_t*)0x20000c2e = 0;
+ *(uint8_t*)0x20000c2f = 0;
+ *(uint8_t*)0x20000c30 = 0;
+ *(uint8_t*)0x20000c31 = 0;
+ *(uint8_t*)0x20000c32 = 0;
+ *(uint8_t*)0x20000c33 = 0;
+ *(uint8_t*)0x20000c34 = 0;
+ *(uint8_t*)0x20000c35 = 0;
+ *(uint8_t*)0x20000c36 = 0;
+ *(uint8_t*)0x20000c37 = 0;
+ *(uint8_t*)0x20000c38 = 0;
+ *(uint8_t*)0x20000c39 = 0;
+ *(uint8_t*)0x20000c3a = 0;
+ *(uint8_t*)0x20000c3b = 0;
+ *(uint8_t*)0x20000c3c = 0;
+ *(uint8_t*)0x20000c3d = 0;
+ *(uint8_t*)0x20000c3e = 0;
+ *(uint8_t*)0x20000c3f = 0;
+ *(uint8_t*)0x20000c40 = 0;
+ *(uint8_t*)0x20000c41 = 0;
+ *(uint8_t*)0x20000c42 = 0;
+ *(uint8_t*)0x20000c43 = 0;
+ *(uint8_t*)0x20000c44 = 0;
+ *(uint8_t*)0x20000c45 = 0;
+ *(uint8_t*)0x20000c46 = 0;
+ *(uint8_t*)0x20000c47 = 0;
+ *(uint8_t*)0x20000c48 = 0;
+ *(uint8_t*)0x20000c49 = 0;
+ *(uint8_t*)0x20000c4a = 0;
+ *(uint8_t*)0x20000c4b = 0;
+ *(uint8_t*)0x20000c4c = 0;
+ *(uint8_t*)0x20000c4d = 0;
+ *(uint8_t*)0x20000c4e = 0;
+ *(uint8_t*)0x20000c4f = 0;
+ *(uint8_t*)0x20000c50 = 0;
+ *(uint8_t*)0x20000c51 = 0;
+ *(uint8_t*)0x20000c52 = 0;
+ *(uint8_t*)0x20000c53 = 0;
+ *(uint16_t*)0x20000c54 = 0xc0;
+ *(uint16_t*)0x20000c56 = 0xe8;
+ *(uint32_t*)0x20000c58 = 0;
+ *(uint64_t*)0x20000c60 = 0;
+ *(uint64_t*)0x20000c68 = 0;
+ *(uint16_t*)0x20000c70 = 0x28;
+ memcpy((void*)0x20000c72,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000",
+ 29);
+ *(uint8_t*)0x20000c8f = 0;
+ *(uint32_t*)0x20000c90 = 0xfffffffe;
+ syscall(__NR_setsockopt, r[0], 0xa02000000000000ul, 0x60ul, 0x20000880ul,
+ 0x418ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/07804ed067fcaa4c8967003831699a24e9b634ed.c b/syzkaller-repros/linux/07804ed067fcaa4c8967003831699a24e9b634ed.c
new file mode 100644
index 0000000..a1b1cf9
--- /dev/null
+++ b/syzkaller-repros/linux/07804ed067fcaa4c8967003831699a24e9b634ed.c
@@ -0,0 +1,736 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/loop.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+struct fs_image_segment {
+ void* data;
+ uintptr_t size;
+ uintptr_t offset;
+};
+
+#define IMAGE_MAX_SEGMENTS 4096
+#define IMAGE_MAX_SIZE (129 << 20)
+
+#define sys_memfd_create 319
+
+static unsigned long fs_image_segment_check(unsigned long size,
+ unsigned long nsegs, long segments)
+{
+ unsigned long i;
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ if (nsegs > IMAGE_MAX_SEGMENTS)
+ nsegs = IMAGE_MAX_SEGMENTS;
+ for (i = 0; i < nsegs; i++) {
+ if (segs[i].size > IMAGE_MAX_SIZE)
+ segs[i].size = IMAGE_MAX_SIZE;
+ segs[i].offset %= IMAGE_MAX_SIZE;
+ if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
+ segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
+ if (size < segs[i].offset + segs[i].offset)
+ size = segs[i].offset + segs[i].offset;
+ }
+ if (size > IMAGE_MAX_SIZE)
+ size = IMAGE_MAX_SIZE;
+ return size;
+}
+
+static long syz_mount_image(volatile long fsarg, volatile long dir,
+ volatile unsigned long size,
+ volatile unsigned long nsegs,
+ volatile long segments, volatile long flags,
+ volatile long optsarg)
+{
+ char loopname[64], fs[32], opts[256];
+ int loopfd, err = 0, res = -1;
+ unsigned long i;
+ NONFAILING(size = fs_image_segment_check(size, nsegs, segments));
+ int memfd = syscall(sys_memfd_create, "syz_mount_image", 0);
+ if (memfd == -1) {
+ err = errno;
+ goto error;
+ }
+ if (ftruncate(memfd, size)) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ for (i = 0; i < nsegs; i++) {
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ int res1 = 0;
+ NONFAILING(res1 =
+ pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset));
+ if (res1 < 0) {
+ }
+ }
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
+ loopfd = open(loopname, O_RDWR);
+ if (loopfd == -1) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ if (errno != EBUSY) {
+ err = errno;
+ goto error_close_loop;
+ }
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ usleep(1000);
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ err = errno;
+ goto error_close_loop;
+ }
+ }
+ mkdir((char*)dir, 0777);
+ memset(fs, 0, sizeof(fs));
+ NONFAILING(strncpy(fs, (char*)fsarg, sizeof(fs) - 1));
+ memset(opts, 0, sizeof(opts));
+ NONFAILING(strncpy(opts, (char*)optsarg, sizeof(opts) - 32));
+ if (strcmp(fs, "iso9660") == 0) {
+ flags |= MS_RDONLY;
+ } else if (strncmp(fs, "ext", 3) == 0) {
+ if (strstr(opts, "errors=panic") || strstr(opts, "errors=remount-ro") == 0)
+ strcat(opts, ",errors=continue");
+ } else if (strcmp(fs, "xfs") == 0) {
+ strcat(opts, ",nouuid");
+ }
+ if (mount(loopname, (char*)dir, fs, flags, opts)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ res = 0;
+error_clear_loop:
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+error_close_loop:
+ close(loopfd);
+error_close_memfd:
+ close(memfd);
+error:
+ errno = err;
+ return res;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void reset_loop()
+{
+ char buf[64];
+ snprintf(buf, sizeof(buf), "/dev/loop%llu", procid);
+ int loopfd = open(buf, O_RDWR);
+ if (loopfd != -1) {
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ close(loopfd);
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 26; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45 + (call == 9 ? 100 : 0));
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[8] = {0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0x0,
+ 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ NONFAILING(*(uint32_t*)0x20000200 = 0);
+ NONFAILING(*(uint32_t*)0x20000204 = 0x70);
+ NONFAILING(*(uint8_t*)0x20000208 = 3);
+ NONFAILING(*(uint8_t*)0x20000209 = 0);
+ NONFAILING(*(uint8_t*)0x2000020a = 0);
+ NONFAILING(*(uint8_t*)0x2000020b = 0);
+ NONFAILING(*(uint32_t*)0x2000020c = 0);
+ NONFAILING(*(uint64_t*)0x20000210 = 0xa);
+ NONFAILING(*(uint64_t*)0x20000218 = 0);
+ NONFAILING(*(uint64_t*)0x20000220 = 0);
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 0, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 1, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 2, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 3, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 4, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 5, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 6, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 7, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 8, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 9, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 10, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 11, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 12, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 13, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 14, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 15, 2));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 17, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 18, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 19, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 20, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 21, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 22, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 23, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 24, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 25, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 26, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 27, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 28, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 29, 35));
+ NONFAILING(*(uint32_t*)0x20000230 = 0);
+ NONFAILING(*(uint32_t*)0x20000234 = 0);
+ NONFAILING(*(uint64_t*)0x20000238 = 0);
+ NONFAILING(*(uint64_t*)0x20000240 = 0);
+ NONFAILING(*(uint64_t*)0x20000248 = 0);
+ NONFAILING(*(uint64_t*)0x20000250 = 0);
+ NONFAILING(*(uint32_t*)0x20000258 = 0);
+ NONFAILING(*(uint32_t*)0x2000025c = 0);
+ NONFAILING(*(uint64_t*)0x20000260 = 0);
+ NONFAILING(*(uint32_t*)0x20000268 = 0);
+ NONFAILING(*(uint16_t*)0x2000026c = 0);
+ NONFAILING(*(uint16_t*)0x2000026e = 0);
+ syscall(__NR_perf_event_open, 0x20000200ul, 0, -1ul, -1, 0ul);
+ break;
+ case 1:
+ syscall(__NR_clock_getres, 0ul, 0ul);
+ break;
+ case 2:
+ syscall(__NR_ioctl, -1, 0xae03ul, 0ul);
+ break;
+ case 3:
+ NONFAILING(*(uint32_t*)0x20000200 = 0);
+ NONFAILING(*(uint32_t*)0x20000204 = 0x70);
+ NONFAILING(*(uint8_t*)0x20000208 = 3);
+ NONFAILING(*(uint8_t*)0x20000209 = 0);
+ NONFAILING(*(uint8_t*)0x2000020a = 0);
+ NONFAILING(*(uint8_t*)0x2000020b = 0);
+ NONFAILING(*(uint32_t*)0x2000020c = 0);
+ NONFAILING(*(uint64_t*)0x20000210 = 8);
+ NONFAILING(*(uint64_t*)0x20000218 = 0);
+ NONFAILING(*(uint64_t*)0x20000220 = 0);
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 0, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 1, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 2, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 3, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 4, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 5, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 6, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 7, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 8, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 9, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 10, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 11, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 12, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 13, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 14, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 15, 2));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 17, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 18, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 19, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 20, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 21, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 22, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 23, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 24, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 25, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 26, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 27, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 28, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000228, 0, 29, 35));
+ NONFAILING(*(uint32_t*)0x20000230 = 0);
+ NONFAILING(*(uint32_t*)0x20000234 = 0);
+ NONFAILING(*(uint64_t*)0x20000238 = 0x20000000);
+ NONFAILING(*(uint64_t*)0x20000240 = 0);
+ NONFAILING(*(uint64_t*)0x20000248 = 0);
+ NONFAILING(*(uint64_t*)0x20000250 = 0);
+ NONFAILING(*(uint32_t*)0x20000258 = 0);
+ NONFAILING(*(uint32_t*)0x2000025c = 0);
+ NONFAILING(*(uint64_t*)0x20000260 = 0);
+ NONFAILING(*(uint32_t*)0x20000268 = 0);
+ NONFAILING(*(uint16_t*)0x2000026c = 0);
+ NONFAILING(*(uint16_t*)0x2000026e = 0);
+ res = syscall(__NR_perf_event_open, 0x20000200ul, 0, -1ul, -1, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 4:
+ res = syscall(__NR_fcntl, r[0], 0ul, -1);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 5:
+ NONFAILING(memcpy((void*)0x20000000, "/dev/dmmidi#\000", 13));
+ res = syz_open_dev(0x20000000, 0x40, 0x22000);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 6:
+ res = syscall(__NR_ioctl, -1, 0xc0086420ul, 0x20000040ul);
+ if (res != -1)
+ NONFAILING(r[3] = *(uint32_t*)0x20000040);
+ break;
+ case 7:
+ NONFAILING(*(uint32_t*)0x20000080 = r[3]);
+ NONFAILING(*(uint32_t*)0x20000084 = 1);
+ syscall(__NR_ioctl, r[2], 0xc0086423ul, 0x20000080ul);
+ break;
+ case 8:
+ NONFAILING(*(uint32_t*)0x20000440 = r[3]);
+ NONFAILING(*(uint32_t*)0x20000444 = 6);
+ NONFAILING(*(uint64_t*)0x20000448 = 0x200002c0);
+ NONFAILING(*(uint32_t*)0x200002c0 = 0x7ff);
+ NONFAILING(*(uint32_t*)0x200002c4 = 2);
+ NONFAILING(*(uint32_t*)0x200002c8 = 9);
+ NONFAILING(*(uint32_t*)0x200002cc = 0xf1);
+ NONFAILING(*(uint32_t*)0x200002d0 = 0);
+ NONFAILING(*(uint32_t*)0x200002d4 = 6);
+ NONFAILING(*(uint64_t*)0x20000450 = 0x20000300);
+ NONFAILING(*(uint32_t*)0x20000300 = 9);
+ NONFAILING(*(uint32_t*)0x20000458 = 4);
+ NONFAILING(*(uint32_t*)0x2000045c = 5);
+ NONFAILING(*(uint32_t*)0x20000460 = 0x600);
+ NONFAILING(*(uint64_t*)0x20000468 = 0x20000380);
+ NONFAILING(*(uint32_t*)0x20000380 = 8);
+ NONFAILING(*(uint32_t*)0x20000384 = 0x70);
+ NONFAILING(*(uint32_t*)0x20000388 = 0x1f);
+ NONFAILING(*(uint32_t*)0x2000038c = 0xffffffc6);
+ NONFAILING(*(uint32_t*)0x20000390 = 0x7e5);
+ NONFAILING(*(uint64_t*)0x20000470 = 0x20000400);
+ NONFAILING(*(uint32_t*)0x20000400 = 1);
+ NONFAILING(*(uint32_t*)0x20000404 = 0x1fe000);
+ NONFAILING(*(uint32_t*)0x20000408 = 5);
+ NONFAILING(*(uint32_t*)0x2000040c = 0xeb8);
+ NONFAILING(*(uint32_t*)0x20000478 = 0);
+ syscall(__NR_ioctl, r[1], 0xc0406429ul, 0x20000440ul);
+ break;
+ case 9:
+ NONFAILING(*(uint64_t*)0x200001c0 = 0x20000000);
+ NONFAILING(memcpy((void*)0x20000000,
+ "\xeb\x3c\x90\x6d\x6b\x66\x73\x2e\x66\x61\x74\x00\x02\x04"
+ "\x01\x00\x02\x00\x02\x74\x00\xf8",
+ 22));
+ NONFAILING(*(uint64_t*)0x200001c8 = 0x16);
+ NONFAILING(*(uint64_t*)0x200001d0 = 0);
+ syz_mount_image(0, 0, 0xe800, 1, 0x200001c0, 0, 0x20000240);
+ break;
+ case 10:
+ NONFAILING(memcpy((void*)0x20021000, "./file0\000", 8));
+ res = syscall(__NR_open, 0x20021000ul, 0ul, 0ul);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 11:
+ syscall(__NR_getdents, -1, 0x20000000ul, 0xd6147cbb6f273a13ul);
+ break;
+ case 12:
+ syscall(__NR_ioctl, -1, 0x7002ul, 0);
+ break;
+ case 13:
+ res = syscall(__NR_socket, 0x29ul, 5ul, 0ul);
+ if (res != -1)
+ r[5] = res;
+ break;
+ case 14:
+ syscall(__NR_sendfile, r[5], -1, 0ul, 0xfffffffful);
+ break;
+ case 15:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[6] = res;
+ break;
+ case 16:
+ syscall(__NR_sendmsg, r[6], 0ul, 0ul);
+ break;
+ case 17:
+ syscall(__NR_ioctl, -1, 0x400454cdul, 0x305ul);
+ break;
+ case 18:
+ syscall(__NR_fchdir, r[4]);
+ break;
+ case 19:
+ NONFAILING(memcpy((void*)0x200001c0, "./bus\000", 6));
+ res = syscall(__NR_open, 0x200001c0ul, 0x141042ul, 0ul);
+ if (res != -1)
+ r[7] = res;
+ break;
+ case 20:
+ NONFAILING(*(uint32_t*)0x20000340 = 0xc);
+ syscall(__NR_getsockopt, -1, 0ul, 0x11ul, 0x20000280ul, 0x20000340ul);
+ break;
+ case 21:
+ NONFAILING(*(uint64_t*)0x200003c0 = 5);
+ syscall(__NR_fcntl, -1, 0x40eul, 0x200003c0ul);
+ break;
+ case 22:
+ syscall(__NR_sched_yield);
+ break;
+ case 23:
+ NONFAILING(*(uint32_t*)0x200000c0 = 0);
+ NONFAILING(*(uint16_t*)0x200000c4 = 0x18);
+ NONFAILING(*(uint16_t*)0x200000c6 = 0xfa00);
+ NONFAILING(*(uint64_t*)0x200000c8 = 0);
+ NONFAILING(*(uint64_t*)0x200000d0 = 0);
+ NONFAILING(*(uint16_t*)0x200000d8 = 0);
+ NONFAILING(*(uint8_t*)0x200000da = 9);
+ NONFAILING(*(uint8_t*)0x200000db = 0);
+ NONFAILING(*(uint8_t*)0x200000dc = 0);
+ NONFAILING(*(uint8_t*)0x200000dd = 0);
+ NONFAILING(*(uint8_t*)0x200000de = 0);
+ NONFAILING(*(uint8_t*)0x200000df = 0);
+ syscall(__NR_write, r[7], 0x200000c0ul, 0x20ul);
+ break;
+ case 24:
+ NONFAILING(*(uint32_t*)0x20000140 = 0);
+ NONFAILING(*(uint16_t*)0x20000144 = 0x18);
+ NONFAILING(*(uint16_t*)0x20000146 = 0xfa00);
+ NONFAILING(*(uint64_t*)0x20000148 = 0);
+ NONFAILING(*(uint64_t*)0x20000150 = 0);
+ NONFAILING(*(uint16_t*)0x20000158 = 0);
+ NONFAILING(*(uint8_t*)0x2000015a = 0);
+ NONFAILING(*(uint8_t*)0x2000015b = 0);
+ NONFAILING(*(uint8_t*)0x2000015c = 0);
+ NONFAILING(*(uint8_t*)0x2000015d = 0);
+ NONFAILING(*(uint8_t*)0x2000015e = 0);
+ NONFAILING(*(uint8_t*)0x2000015f = 0);
+ syscall(__NR_write, r[7], 0x20000140ul, 0x20ul);
+ break;
+ case 25:
+ NONFAILING(*(uint64_t*)0x20000040 = 0);
+ syscall(__NR_sendfile, r[7], r[7], 0x20000040ul, 0x8080fffffffeul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ for (procid = 0; procid < 6; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0882292577b73fb3a92d45780882a121aa896b83.c b/syzkaller-repros/linux/0882292577b73fb3a92d45780882a121aa896b83.c
new file mode 100644
index 0000000..4e9917c
--- /dev/null
+++ b/syzkaller-repros/linux/0882292577b73fb3a92d45780882a121aa896b83.c
@@ -0,0 +1,317 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x200000c0, "/dev/dri/card#\000", 15);
+ res = syz_open_dev(0x200000c0, 0x200, 0x101000);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000000, "/dev/ion\000", 9);
+ res =
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0x141080ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000040 = 0xa925;
+ *(uint32_t*)0x20000048 = 0x2b;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = -1;
+ *(uint32_t*)0x20000054 = 0;
+ res = syscall(__NR_ioctl, r[1], 0xc0184900ul, 0x20000040ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000050;
+ res = syscall(__NR_dup, r[2]);
+ if (res != -1)
+ r[3] = res;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = r[3];
+ syscall(__NR_ioctl, r[0], 0xc00c642eul, 0x20000080ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/08cce7d51dda77c5900eaedcc3a6acf2f5ad0d3e.c b/syzkaller-repros/linux/08cce7d51dda77c5900eaedcc3a6acf2f5ad0d3e.c
new file mode 100644
index 0000000..9aac60e
--- /dev/null
+++ b/syzkaller-repros/linux/08cce7d51dda77c5900eaedcc3a6acf2f5ad0d3e.c
@@ -0,0 +1,280 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 3; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syz_open_dev(0, 0, 0);
+ break;
+ case 1:
+ NONFAILING(memcpy((void*)0x20000000, "/dev/fd#\000", 9));
+ res = syz_open_dev(0x20000000, 0, 0x841);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ NONFAILING(*(uint8_t*)0x20000040 = 0x8a);
+ NONFAILING(*(uint64_t*)0x20000048 = 6);
+ NONFAILING(*(uint64_t*)0x20000050 = 5);
+ NONFAILING(*(uint64_t*)0x20000058 = 0x10001);
+ NONFAILING(*(uint64_t*)0x20000060 = 0);
+ NONFAILING(*(uint64_t*)0x20000068 = 9);
+ NONFAILING(*(uint64_t*)0x20000070 = 0x1000);
+ NONFAILING(*(uint8_t*)0x20000078 = 8);
+ NONFAILING(*(uint8_t*)0x20000079 = 1);
+ NONFAILING(*(uint8_t*)0x2000007a = 0x40);
+ NONFAILING(*(uint8_t*)0x2000007b = 2);
+ NONFAILING(*(uint64_t*)0x20000080 = 0x10001);
+ NONFAILING(*(uint8_t*)0x20000088 = 9);
+ NONFAILING(*(uint32_t*)0x2000008c = 0x51);
+ NONFAILING(*(uint32_t*)0x20000090 = 0x7f);
+ NONFAILING(*(uint32_t*)0x20000094 = 0);
+ NONFAILING(*(uint32_t*)0x20000098 = 0x200);
+ NONFAILING(*(uint32_t*)0x2000009c = 1);
+ NONFAILING(*(uint8_t*)0x200000a0 = 2);
+ NONFAILING(*(uint8_t*)0x200000a1 = 3);
+ NONFAILING(*(uint16_t*)0x200000a2 = 0x2529);
+ NONFAILING(*(uint16_t*)0x200000a4 = 0xf344);
+ NONFAILING(*(uint16_t*)0x200000a6 = 8);
+ NONFAILING(*(uint16_t*)0x200000a8 = 0x405b);
+ NONFAILING(*(uint16_t*)0x200000aa = 2);
+ NONFAILING(*(uint16_t*)0x200000ac = 0xae6);
+ NONFAILING(*(uint16_t*)0x200000ae = 0);
+ NONFAILING(*(uint16_t*)0x200000b0 = 0);
+ NONFAILING(*(uint32_t*)0x200000b4 = 0);
+ NONFAILING(*(uint32_t*)0x200000b8 = 1);
+ syscall(__NR_ioctl, r[0], 0x40800290, 0x20000040);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/08e23caab6df4fcf8d6e276eeb4e76b2593478f4.c b/syzkaller-repros/linux/08e23caab6df4fcf8d6e276eeb4e76b2593478f4.c
new file mode 100644
index 0000000..3535174
--- /dev/null
+++ b/syzkaller-repros/linux/08e23caab6df4fcf8d6e276eeb4e76b2593478f4.c
@@ -0,0 +1,806 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 2ul, 2ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000600, "bridge_slave_1\000\000", 16);
+ *(uint32_t*)0x20000610 = 0;
+ res = syscall(__NR_ioctl, r[0], 0x8933ul, 0x20000600ul);
+ if (res != -1)
+ r[1] = *(uint32_t*)0x20000610;
+ *(uint64_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint64_t*)0x20000250 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000280;
+ memcpy((void*)0x20000280,
+ "\xcc\x00\x00\x00\x24\x00\x07\x8f\x96\xcd\x03\x37\xcc\xc5\x5e\xb2\x98"
+ "\x92\xa1\x37",
+ 20);
+ *(uint32_t*)0x20000294 = r[1];
+ memcpy(
+ (void*)0x20000298,
+ "\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x09\x00\x01\x00\x6e\x65"
+ "\x74\x65\x6d\x00\x00\x00\x4c\x00\x02\x00\x00\x00\x00\x00\x00\x23\x58\x48"
+ "\x48\x00\x00\x00\x00\x00\x00\x00\x00\xb2\x00\x00\x00\x00\x00\x00\x0c\x00"
+ "\x04\x00\x00\x00\xed\x6f\x65\x00\x00\x00\x0c\x00\x05\x00\x05\x22\x02\x00"
+ "\x00\x00\x00\x00\x0c\x00\x0b\x00\x00\x00\x00\x80\x00\x00\x00\x00\x0c\x00"
+ "\x03\x00\x00\x00\x00\x01\x00\x68\x74\xe9\xac\x68\x31\xbd\x62\x5d\x65\x05"
+ "\x00\x08\x00\x00\x00\x00\x00\x05\x00\x36\xba\x51\xa9\xec\xc5\xdd\x7f\xca"
+ "\x93\x66\xa9\xb5\x0c\xe6\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\xf3\xff"
+ "\x04\x02\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x02\x00"
+ "\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\xd5\xc0\x0e\x37\x12\x26\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00"
+ "\x02\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x00\xcf\xf6"
+ "\xae\x85\xf6\x23\xc1\xc7\x41\x0e\x1c\x94\xe0\xa1\x89\x12\xc2\x39\x89\x3b"
+ "\xa7\xee\x18\xe6\xb8\x7c\xc7\xeb\x42\x53\x57\xf8\x3f\xee\x96\xc9\xc3\x0b"
+ "\x2a\x9b\xde\xb9\x14\x79\xea\xfd\x9d\x18\xe6\x30\xab\xfb\x4a\x80\x9c\x74"
+ "\x26\x4f\x1c\xb2\x8e\xf7\xac\x3d\x3c\x34\xaf\x4a\x07\x9b\xd7\x52\x5e\x67"
+ "\x2a\x53\xa4\xd2\xd3\xe8\xa6\x05\x37\x06\x00\x00\x00\xcd\xea\xca\xa2\x61"
+ "\xe5\x20\x6c\xdd\x3e\xa4\xa8\x90\x5b\xf3\xf5\x9c\x38\x9a\x9f\xba\x15\x18"
+ "\xa2\x2b\xa4\x81\x89\xbf\x31\x36\x94\x41\x58\x78\x2e\x76\x64\x20\x65\xa0"
+ "\xa8\x46\x21\xeb\x10\x5a\xb7\x92\xa1\x86\xdf\x6d\x5d\x5b\xb7\x98\x00\x00"
+ "\x00\x00\x00\x00\x00",
+ 383);
+ *(uint64_t*)0x200000c8 = 0xcc;
+ *(uint64_t*)0x20000258 = 1;
+ *(uint64_t*)0x20000260 = 0;
+ *(uint64_t*)0x20000268 = 0;
+ *(uint32_t*)0x20000270 = 0;
+ syscall(__NR_sendmsg, -1, 0x20000240ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 0x80002ul, 0);
+ if (res != -1)
+ r[2] = res;
+ *(uint64_t*)0x20000180 = 2;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0x20000080;
+ *(uint64_t*)0x20000198 = 0xe;
+ *(uint64_t*)0x200001a0 = 0x20000100;
+ *(uint64_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001b0 = 0;
+ syscall(__NR_sendmmsg, r[2], 0x20000180ul, 0x492492492492642ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0931801760a41b10cdc222d906b87096dfbc699b.c b/syzkaller-repros/linux/0931801760a41b10cdc222d906b87096dfbc699b.c
new file mode 100644
index 0000000..3801120
--- /dev/null
+++ b/syzkaller-repros/linux/0931801760a41b10cdc222d906b87096dfbc699b.c
@@ -0,0 +1,20 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+void loop()
+{
+ syscall(__NR_shmget, 0, 0, 0, 0x20b39000);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/09a650f7fd6360cfe594f52776cd08e4dea82d6f.c b/syzkaller-repros/linux/09a650f7fd6360cfe594f52776cd08e4dea82d6f.c
new file mode 100644
index 0000000..e2c2394
--- /dev/null
+++ b/syzkaller-repros/linux/09a650f7fd6360cfe594f52776cd08e4dea82d6f.c
@@ -0,0 +1,337 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0x70;
+ *(uint8_t*)0x200000c8 = 3;
+ *(uint8_t*)0x200000c9 = 0;
+ *(uint8_t*)0x200000ca = 0;
+ *(uint8_t*)0x200000cb = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint64_t*)0x200000d0 = 8;
+ *(uint64_t*)0x200000d8 = 0;
+ *(uint64_t*)0x200000e0 = 0;
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 0, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 1, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 2, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 3, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 4, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 5, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 6, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 7, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 8, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 9, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 10, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 11, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 12, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 13, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 14, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 15, 2);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 17, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 18, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 19, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 20, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 21, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 22, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 23, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 24, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 25, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 26, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 27, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 28, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200000e8, 0, 29, 35);
+ *(uint32_t*)0x200000f0 = 0;
+ *(uint32_t*)0x200000f4 = 0;
+ *(uint64_t*)0x200000f8 = 0;
+ *(uint64_t*)0x20000100 = 0;
+ *(uint64_t*)0x20000108 = 0;
+ *(uint64_t*)0x20000110 = 0;
+ *(uint32_t*)0x20000118 = 0;
+ *(uint32_t*)0x2000011c = 0;
+ *(uint64_t*)0x20000120 = 0;
+ *(uint32_t*)0x20000128 = 0;
+ *(uint16_t*)0x2000012c = 0;
+ *(uint16_t*)0x2000012e = 0;
+ syscall(__NR_perf_event_open, 0x200000c0, 0, -1, -1, 0);
+ memcpy((void*)0x20000040, "./file0\000", 8);
+ res = syscall(__NR_open, 0x20000040, 0x141042, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000140 = 1;
+ *(uint64_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0;
+ *(uint64_t*)0x20000158 = 0;
+ *(uint8_t*)0x20000160 = 0;
+ *(uint8_t*)0x20000161 = 1;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint64_t*)0x20000170 = 0;
+ *(uint64_t*)0x20000178 = 0;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint64_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0;
+ *(uint64_t*)0x20000198 = 0;
+ *(uint64_t*)0x200001a0 = 0;
+ syscall(__NR_write, r[0], 0x20000140, 0x68);
+ *(uint64_t*)0x200001c0 = 0;
+ syscall(__NR_sendfile, r[0], r[0], 0x200001c0, 0xa198);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/09e1ccbb75f46c836bdb470380be658050e66942.c b/syzkaller-repros/linux/09e1ccbb75f46c836bdb470380be658050e66942.c
new file mode 100644
index 0000000..9f7faa0
--- /dev/null
+++ b/syzkaller-repros/linux/09e1ccbb75f46c836bdb470380be658050e66942.c
@@ -0,0 +1,403 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ exit(1);
+ }
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000008 = 0x500;
+ *(uint64_t*)0x20000010 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000100;
+ *(uint32_t*)0x20000100 = 0x38;
+ *(uint16_t*)0x20000104 = 0x1403;
+ *(uint16_t*)0x20000106 = 1;
+ *(uint32_t*)0x20000108 = 0;
+ *(uint32_t*)0x2000010c = 0;
+ *(uint16_t*)0x20000110 = 9;
+ *(uint16_t*)0x20000112 = 2;
+ memcpy((void*)0x20000114, "syz1\000", 5);
+ *(uint16_t*)0x2000011c = 8;
+ *(uint16_t*)0x2000011e = 0x41;
+ memcpy((void*)0x20000120, "rxe\000", 4);
+ *(uint16_t*)0x20000124 = 0x14;
+ *(uint16_t*)0x20000126 = 0x33;
+ memcpy((void*)0x20000128, "syz_tun\000\000\000\000\000\000\000\000\000", 16);
+ *(uint64_t*)0x200000c8 = 0x38;
+ *(uint64_t*)0x20000018 = 1;
+ *(uint64_t*)0x20000020 = 0;
+ *(uint64_t*)0x20000028 = 0;
+ *(uint32_t*)0x20000030 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000000ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0ab3f49f61f5706bf7883fa10ec9961175f74906.c b/syzkaller-repros/linux/0ab3f49f61f5706bf7883fa10ec9961175f74906.c
new file mode 100644
index 0000000..32ecffb
--- /dev/null
+++ b/syzkaller-repros/linux/0ab3f49f61f5706bf7883fa10ec9961175f74906.c
@@ -0,0 +1,100 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 9ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x200004c0 = 0;
+ *(uint32_t*)0x200004c8 = 0;
+ *(uint64_t*)0x200004d0 = 0x20000480;
+ *(uint64_t*)0x20000480 = 0x20000000;
+ memcpy(
+ (void*)0x20000000,
+ "\x20\x04\x00\x00\xf4\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x08\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5"
+ "\xb9\xff\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4b\xe0"
+ "\x59\x72\x77\x02\xab\x76\x2a\x16\x63\x28\x94\xf9\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6e\x6e\xf9\xc5\xf1\x87"
+ "\x65\xfc\x7c\x8c\xc9\xc7\x07\xb8\x1b\xec\x5b\x72\x0a\xff\xc3\xfd\x54\x1b"
+ "\x90\x97\xd0\x0e\xf5\x0b\x0d\x58\xf3\x76\x09\x9b\xc3\x78\x51\x39\x20\xc9"
+ "\xa0\xf8\x87\x69\x35\x48\xd0\xf7\x7e\xf0\x69\x96\xf2\x1d\x23\x2d\xe5\x38"
+ "\x7f\x2c\x43\xea\xe6\x22\x9f\x61",
+ 1124);
+ *(uint64_t*)0x20000488 = 0x420;
+ *(uint64_t*)0x200004d8 = 1;
+ *(uint64_t*)0x200004e0 = 0;
+ *(uint64_t*)0x200004e8 = 0;
+ *(uint32_t*)0x200004f0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x200004c0ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0bf321e31faa1d3d4b7c3c8930bc317288d05378.c b/syzkaller-repros/linux/0bf321e31faa1d3d4b7c3c8930bc317288d05378.c
new file mode 100644
index 0000000..0602970
--- /dev/null
+++ b/syzkaller-repros/linux/0bf321e31faa1d3d4b7c3c8930bc317288d05378.c
@@ -0,0 +1,437 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000080, "/dev/uhid\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000080ul, 2ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy(
+ (void*)0x20000bc0,
+ "\x0b\x00\x00\x00\x73\x79\x7a\x31\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf3\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x01\x00\x73\x8d\x7a\x31\x00\x00\x00\x00\x00\xff\x07\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x73\x79"
+ "\x7a\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\xcf\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3b\x38\xe9\x67\xac\x82\x06\xea"
+ "\xae\x86\xb9\x7e\xec\x0b\x2b\xed\x1e\xe2\x33\x64\xb1\x0d\x6a\xad\x51\x02"
+ "\x00\x00\x00\xe2\xa1\xdb\x3c\x6a\x0d\xee\x4a\xfc\x66\xd2\x44\x28\x05\x20"
+ "\x1c\x39\x38\x9a\x80\x4c\x41\xc2\x99\x3f\xc6\x7e\x8a\x14\x60\x45\xe1\x4a"
+ "\x8a\x08\x00\x55\x0e\x6a\x25\xc0\xef\x65\xf6\xec\x71\xf0\x08\x42\x54\xd1"
+ "\x40\x18\x7f\xaf\xa4\xa1\xee\x6e\xce\x53\xc6\x73\x85\xb8\x83\xa3\x6a\xd2"
+ "\x4a\x04\x00\x00\x00\x00\x00\x00\x00\x6a\x8a\xb1\x1b\x0a\x0b\x00\xe7\x7e"
+ "\x6c\x16\x18\x9c\xfa\x16\xcb\xe0\x1a\x4c\xe4\x11\x37\x8e\xaa\xb7\x37\x2d"
+ "\xab\x5e\xef\x84\xc3\x1b\x2d\xad\x86\x8a\x53\xe6\xf5\xe6\x97\x46\xa7\x1e"
+ "\xc9\x2d\xca\xa9\xa7\xdf\xab\x39\x42\x86\xe5\xc8\x1e\xae\x45\xe3\xa2\x5b"
+ "\x94\x2b\x8d\xa1\x1e\xdb\x57\x8b\x45\x3a\xca\xc0\x3a\x9d\x34\x48\x00\x00"
+ "\x00\x00\x83\xd6\xd5\xfe\x4f\x83\x3d\x4d\x4c\xfb\xee\xf0\xe0\xe6\x2b\xe2"
+ "\x05\x00\x00\x00\x3c\x32\x98\x4c\x6c\x4b\x2b\x9c\x33\xd8\xa6\x24\xce\xa9"
+ "\x5c\x3b\x3c\x6d\xd8\x73\x56\x9c\xf4\x78\x6f\xc5\x16\x6b\x03\x00\x00\x00"
+ "\x00\x00\x1f\xf2\x8d\x3c\xe3\xe3\xb8\xf8\x1e\x34\xcf\x97\xc9\xc8\x41\xcb"
+ "\x2e\xf0\x81\x07\xa9\xa9\x65\x49\xe3\xd2\x59\xdf\x17\xe2\x9e\xd6\x4b\xd6"
+ "\x12\x08\x13\xf9\xf0\x34\x4e\x13\x95\x06\x70\x1e\x8f\xde\xdb\x06\x00\x9b"
+ "\x5e\x4d\x0c\x67\xbd\xa0\xb9\x28\xb7\x32\xcf\xf7\x82\xb0\x68\x40\x75\xf2"
+ "\xcb\x78\x51\xef\xdd\x77\x97\xee\x95\xd2\xac\x28\xa8\xca\xbd\x26\xc1\x56"
+ "\x82\xaa\x58\xd3\x1a\xec\x95\x6b\xd7\xc2\x78\x06\x40\x34\x34\xb3\xc3\x0b"
+ "\x07\x0b\xcc\x82\x66\xe1\x2f\xa6\x66\x02\x05\x62\x56\xf7\x46\x75\xb7\xcb"
+ "\x6a\x2c\xd9\x1a\x59\xde\x4d\x87\xb2\x70\x8d\x70\xc8\xf3\xdf\x53\xca\xf8"
+ "\xfe\x18\x0c\x4d\xea\x3f\x5b\x7a\x87\x1b\x30\xc7\xa5\x75\x3b\x48\xf7\xf0"
+ "\x91\x92\xa3\x4b\x0e\xfa\xab\x02\xdc\xa0\x51\x7e\xee\x10\xff\x30\x20\x6f"
+ "\x78\xec\x82\xc7\x2f\xe0\x08\x30\x83\x1d\xcd\x6e\x9d\xe6\xc6\x20\xa0\xe8"
+ "\xe0\xd0\x57\x0b\x43\x99\x41\x71\x3e\xf2\x8d\xdd\x5f\x84\x47\xbb\xf7\xa7"
+ "\xbc\xdc\x9d\x94\xa5\xdb\x17\x8b\x64\xa5\x5d\xc0\xd3\x73\xad\x4e\xf5\x58"
+ "\x00\x37\xea\x20\xb3\x4b\x2b\x0c\x88\x75\xac\xf8\x90\x9f\xe0\x50\xd6\x2e"
+ "\xe8\x5d\x1b\x3e\xa8\x76\xab\x40\x8e\xd3\xdf\x53\x1e\x79\x82\x3e\xb4\x05"
+ "\x6a\xa3\x3a\xe9\x20\x76\x46\xab\x9b\xa6\xd7\x93\x41\x22\x0d\x7c\x52\xe6"
+ "\x97\xd4\x04\x09\xc0\xb4\x65\x9a\x42\x98\x9d\x56\x79\x92\x71\x44\xa7\x19"
+ "\x68\x1c\x7b\xdf\x46\x1a\x34\x77\x5c\x75\x23\x69\xa1\x63\x6c\x92\xa2\xdf"
+ "\xc8\x68\xed\x0b\x3e\xa8\x49\x6f\xbe\xb1\x80\x8d\x7f\xd3\xa4\xfd\x4d\x52"
+ "\x1b\xc2\x44\x30\x6a\x13\xe3\x04\xf2\x0c\xb0\x3e\x7a\x54\x26\x42\x2f\x9b"
+ "\x91\xf2\xd4\x4c\x99\x9e\x21\xc6\xba\xcf\xf3\xbc\xa0\xd0\x3b\x95\x13\xe8"
+ "\x7f\xee\xf4\xb3\xca\x5c\xc4\x2e\x60\x26\x7a\x47\x8f\xa1\x1a\xb4\x6f\xc3"
+ "\x81\x2f\x75\xba\x64\x0d",
+ 924);
+ syscall(__NR_write, r[0], 0x20000bc0ul, 0x12eul);
+ *(uint32_t*)0x20000300 = 8;
+ memcpy(
+ (void*)0x20000304,
+ "\xed\x4d\x2b\x70\x42\x8a\x2f\x63\x9e\xa9\xd5\x21\xe6\xff\x44\xdb\x2b\xc3"
+ "\x09\xbf\x0c\xd1\x00\x7c\x83\x31\xc0\xb0\xf4\x6e\x2e\xa0\xd8\xa9\xe8\xbb"
+ "\xcc\x4e\x8a\xf5\x3d\x63\xef\x9b\xdc\xe3\x8c\x83\xf4\x9d\xc1\x7e\xe9\xf2"
+ "\x55\x0f\x5a\x1b\x5d\x21\x62\x86\x9a\x7c\x72\x27\x51\x54\xfb\xa2\x9d\x0e"
+ "\x18\x61\x12\x6a\xe7\xa6\x66\xd1\xd0\xf0\x65\x6b\xbe\xd7\xf8\x5a\xbe\x1d"
+ "\x5b\x67\x97\x38\x0f\xb4\x7b\x47\x0c\xcb\x0b\x62\xc4\xe2\xf7\x45\xba\x6d"
+ "\x39\x95\x8e\xfe\xcd\xf2\x72\xec\x25\x48\x0f\xad\xc0\xb4\xd7\xe0\x6e\x27"
+ "\xe0\x61\x42\xa9\xc8\x32\xbd\x47\xb0\x3e\xf5\x19\x35\x2e\x5c\x67\xcd\x2a"
+ "\x0c\xd5\x31\x09\x59\x7f\xd0\xad\x07\x6c\x22\x3c\x69\x13\x75\x5f\x2c\x66"
+ "\x1a\x13\xc9\xbb\x95\x6d\x6a\xf4\x7c\xfd\x35\x78\x76\x9d\xeb\xbc\x99\xc8"
+ "\xbf\xf7\x06\x9e\xc7\x20\x4a\x00\x75\xcb\x7d\xb6\x90\x7b\x47\x47\xcb\x4b"
+ "\x66\x4c\x66\x4b\xb3\x77\x81\xf6\x37\x7b\xc3\x0d\x8a\x3c\xe0\x97\x9a\x6e"
+ "\xc0\x09\x73\xdb\x0d\x0d\x14\x76\xb2\xa9\x23\xce\xe6\x70\x6f\x10\xa9\x1e"
+ "\x8d\x92\x80\xcf\xb7\x10\x8e\x2f\x19\x49\xb9\x3c\xa0\x06\x5e\x9f\xa2\xc8"
+ "\xff\x21\xbc\xfd\xdd\xcb\xd7\xbd\x9f\x28\x2d\xd4\x6e\x55\x0c\x3d\xde\x68"
+ "\x60\x00\xbb\x94\x8d\x8f\x79\x00\x81\xc4\x28\x9e\xda\x17\x15\xde\x3f\x49"
+ "\xf6\xd2\x1f\xc4\x64\xe2\xc8\x25\x54\xff\x13\x99\x8b\xe2\xba\xf2\x32\xb7"
+ "\x77\x41\x5a\x66\xd1\x73\x3f\x23\x91\x5c\x27\x2b\xe7\x98\x1b\xc0\xb6\x56"
+ "\x9b\xf6\x74\x0c\x36\xcf\xc7\x7a\x47\xa8\x67\xe1\x3e\x6e\x57\xb1\xf8\x78"
+ "\x34\xb9\x5c\x18\x8d\x5c\xbf\xb3\xe3\x7c\xce\xc4\xd0\xcd\xce\x75\x18\xc1"
+ "\x5e\x8e\x1b\x1c\xd1\xf7\x57\x8d\x09\x5a\x47\x58\x28\x9d\xfa\xdb\x07\x3e"
+ "\x02\x6e\x02\xc8\xf8\xf0\x30\x39\x83\x00\x18\x41\x6c\x4d\x50\x21\x7a\xa8"
+ "\x8a\xdb\x35\x1a\xfc\x2e\x8a\x07\x6e\xb4\x3a\x83\x87\x8d\x2d\x19\x6a\x21"
+ "\x4a\x80\x96\xe8\x66\x33\x62\xd2\x06\x82\xa6\xca\x22\x81\x19\xc5\x7d\x37"
+ "\xac\xb9\x32\x9f\xe6\xd4\x1f\x1b\xec\xe6\x33\x4b\xe5\xda\xc1\x5e\x77\x87"
+ "\x3d\xde\x52\xae\xb5\xa9\xe4\x30\x19\x69\xfb\x40\x81\x6b\x27\xee\x57\xe9"
+ "\x76\xd0\xeb\x3c\x56\xc0\x34\x06\x7e\x58\xa3\x91\xf5\xba\x6e\xf8\x8b\x06"
+ "\xb5\xfc\xe2\x13\x44\x02\x76\x61\x91\x01\x25\xf9\x7f\x22\xd1\xf9\x6c\x04"
+ "\xeb\x48\x2f\x70\x4c\x27\x99\x36\x70\xcd\x87\x0c\xa5\x24\xd1\x93\x44\xc7"
+ "\xb2\xef\x72\xb2\xad\x4b\x4f\x31\x0a\x02\x69\x49\xfe\x9a\xb6\x9f\xcb\x93"
+ "\x5d\xd8\x3f\x47\xa9\x93\x66\x5a\x59\xb5\x4b\xa9\xde\xdc\xca\xf3\x1b\x6e"
+ "\xcf\xe9\x65\x4d\xe2\x02\x19\x13\x53\x57\xfd\x08\x93\x79\xae\xe7\x50\xf5"
+ "\x44\x7f\xb5\x6c\x53\x34\x11\x40\xeb\xa3\xbe\x19\xcc\x85\xbc\x34\x07\x53"
+ "\xa0\xb6\x3b\x3b\xe7\x21\x2d\x6b\x87\xc5\x29\x64\x6d\x55\x2e\x69\xde\x9a"
+ "\x3b\x28\xdb\xd2\x63\x32\x39\x73\x5c\x03\x8e\x0e\x3f\xd7\x84\xdc\x9e\xce"
+ "\xf2\x9b\xf3\x1e\x3f\x0f\x8a\xff\x97\x30\x37\xf2\x16\x14\xa7\xb2\x92\x37"
+ "\x3e\xf7\xda\xdf\x51\x8f\x4c\xed\x8e\xf2\xb8\x6d\xf3\x6e\x50\xc7\x69\xad"
+ "\x43\xdc\x2e\x24\x58\xa7\x41\x4e\x82\x86\xaa\x0b\xc3\x52\xe4\x99\xf7\x14"
+ "\xbf\xd0\xf2\x1b\x70\xfb\x53\x24\x0a\x5a\x2c\xc4\x9f\x02\x32\xba\xba\x28"
+ "\x79\xf8\x7f\xb8\x84\x3e\x01\xab\xb6\x16\x61\xa6\x53\x6d\xe0\x73\xd9\x8e"
+ "\x51\xe9\x73\x62\x26\x62\x5c\x76\x5e\xbb\x11\x88\x91\xdb\xa2\xc3\x15\xf0"
+ "\x21\x15\x30\x26\x0f\xe1\x55\x8c\xef\x91\x6d\x4b\x83\xb0\x66\x27\xc3\xc8"
+ "\x78\x5b\xb4\xbd\x68\x04\x50\xad\x16\xeb\xc0\xbe\x67\x40\x0d\x48\xdd\x66"
+ "\x66\xd7\xf8\x67\x46\x64\xe8\xc3\xc5\x85\xf2\x09\x96\x46\x04\xab\xc2\x98"
+ "\xb3\x8f\xc7\x28\xba\xf0\x69\x3d\xc6\x96\x78\xd6\x4d\xd0\x95\x64\xe5\x6a"
+ "\x17\x4c\x8a\x94\x53\x03\x55\x34\xd0\x47\xf2\xf4\x24\x0c\xb2\x51\xb7\xd8"
+ "\x01\x30\xe5\x81\x93\x88\x1b\xc9\x72\x89\x23\xfd\x75\x8b\x9b\x14\x48\x65"
+ "\xf8\xde\x24\x5d\xc8\x6f\xa9\xf3\x3b\x6f\xdf\x8e\x6b\xbe\x3a\x88\x83\x99"
+ "\xff\xde\x11\x3f\xde\x69\x10\x55\x76\x3a\xa8\x66\x2e\x89\x65\x29\xea\xbc"
+ "\xf8\x58\x9a\xbd\xec\x04\x70\x3d\x4a\x4f\x52\x9c\x4c\x85\xe1\x5f\x9c\xe9"
+ "\xbe\x67\xf4\x46\x9b\x06\xb8\xca\xf2\x44\xf1\xca\xe7\xae\x34\x70\x7a\x78"
+ "\x26\xd2\x5b\xcf\x53\x01\x0a\x38\x27\x67\xad\x44\x48\x53\x63\x67\x7a\x87"
+ "\x96\x31\x28\x8a\x84\x96\x05\x96\x16\x99\xff\x7a\xfe\xde\xc5\x1f\x6b\x72"
+ "\xf6\xb7\xc8\xa2\x4d\xc1\xe0\x40\xc9\x22\x9a\x22\x1c\x8b\x53\xbb\x1e\x04"
+ "\xb2\x11\xb5\x83\x53\xc7\x10\xad\xdb\xfb\x86\xbe\x55\x63\x15\x56\x35\xd9"
+ "\x64\x09\xc8\xd5\xe9\x8c\xa3\x93\xb0\xac\x98\xd8\x63\x9b\x63\xc6\xf5\x9f"
+ "\xf2\x9f\xf7\x8f\xc9\x6a\xaa\x97\x6f\x82\xa5\x59\xb3\xb8\xcb\x19\x98\xcd"
+ "\x5a\x26\x9a\x7e\xde\x5b\x88\x8b\x86\x69\x72\x93\x23\x6c\x77\x9a\xdf\xf4"
+ "\x1d\xfd\x81\x53\xbe\x2c\xb3\x2b\x3f\xaa\x22\x3c\x0c\x30\xe8\xe9\xf5\xb9"
+ "\x55\xa7\xc9\xcd\xf9\xc3\x68\x3b\x5b\x91\x2c\x1e\x80\xef\xa7\x39\x0c\xeb"
+ "\x25\x1a\x71\x95\xa5\x2d\x25\x49\xbe\xc4\x2d\x5b\x4e\xa8\xf0\x06\x20\xf6"
+ "\x54\x2d\x3a\x92\x31\x0a\x7b\x12\xab\xed\xc2\xdf\x8d\x0e\x45\xa5\xfc\xe8"
+ "\x3b\xe1\x9b\x68\xac\xac\x6a\x6d\x93\x7a\x87\x80\x36\x92\x7d\xde\x71\xe7"
+ "\xd4\xd2\xcb\x0a\xe0\x7a\x89\xdc\x03\xc7\xf5\x41\xcd\x05\x3f\x6d\xd1\x0f"
+ "\xbc\x51\x16\x52\x0e\xe6\x66\xcb\xe0\x3b\x31\x65\xbd\x22\x86\xb2\xd2\xc4"
+ "\x62\xb6\xfc\x12\xbf\xf1\x4f\x2e\x80\x66\xb1\x42\x3a\x36\x49\x9d\x1b\x87"
+ "\xa5\x8b\xb8\x12\x76\x1a\xe8\x1f\x87\xc6\x6d\x2f\xbb\x4d\xfa\x83\x8f\x4b"
+ "\x88\xa8\xf2\x1e\xf7\x51\xef\xf2\xec\x33\xff\xf5\x33\x3b\xa3\xd9\xb1\x29"
+ "\x52\xa4\xe6\x53\xbb\x57\xb1\x8d\x98\x64\x1d\x68\xf0\x8d\xbd\x0f\xaa\x92"
+ "\xcb\xa9\x03\x4a\x42\xed\x75\x69\xdb\xb8\x5f\x6e\x33\xc4\xb5\x30\x43\x67"
+ "\xe5\x82\xc6\xf2\xfb\x80\x43\xdc\xfb\xf4\x5a\x1a\x5a\xdb\xb5\x92\xc0\xbb"
+ "\x6e\x36\xed\x74\x25\xa2\x9b\x8d\xbd\x8f\x30\x67\x97\x64\x2a\xa6\xd3\x3c"
+ "\x15\xec\xf2\x65\x81\xc7\x43\x7e\x5d\xba\x45\x41\x91\xec\x8b\xa3\x25\xfc"
+ "\xd8\xe0\x9f\xd3\x14\xe3\xfa\x12\x99\x94\x9f\x19\x39\x73\x26\x80\x93\x0f"
+ "\x4b\x52\x30\xb3\x62\xdb\x56\x8a\x9e\x0a\xff\x70\x81\x4d\x33\xb0\x16\xb6"
+ "\x1a\x61\x77\x14\xab\xde\xe1\x28\xdd\x8c\x70\x82\x8c\xa5\xb7\x02\x65\x58"
+ "\x0b\x70\xa4\x6b\x19\xfa\x51\x99\x4a\x89\x5b\x89\x53\x29\xb7\x85\x76\x8b"
+ "\x09\xe5\xab\x00\x66\x8e\x72\x43\xf3\x6e\x19\x56\x13\x3a\x0f\xfe\xbb\x38"
+ "\xce\xdb\x25\x9b\x69\x44\xe0\x2e\x4a\x1e\x41\xe8\x31\x0d\x8e\x57\x9a\x93"
+ "\x71\x26\x43\x8d\x98\x09\x46\x32\xf2\x19\x1d\x97\x13\x32\x96\xa2\xa4\x19"
+ "\x3a\xee\x8d\xd4\x3f\x20\x0f\x34\x7d\xea\x42\xc8\xcb\xaa\x21\x5e\x94\x11"
+ "\x0c\xc4\x7b\xe1\xfb\x98\xa1\xe2\xd9\x22\xa8\x0b\x60\x6d\x0d\xcc\x8d\xd9"
+ "\xed\x9f\xa1\xff\xe2\x9b\x85\x25\xdb\x54\x1b\xd7\xf0\xf8\x4e\xcd\xf8\x90"
+ "\xdd\x22\x67\x9c\xf4\x38\xef\x07\xdc\x93\xed\x35\x4e\xdc\xcf\xe5\xd4\x59"
+ "\x16\x62\x5d\xbd\xee\xf5\x14\x29\x9b\xaa\xda\x56\x30\x86\x40\x8e\x93\x08"
+ "\x32\x4d\xa0\x0d\xe9\x74\x37\x43\xd4\xa6\x44\x75\x7b\xf1\x4b\x83\x66\x39"
+ "\x29\xc5\x51\x84\xd0\xed\xef\x23\x81\x61\xac\x28\x01\x26\x1e\x5f\x07\x77"
+ "\x67\xb3\x7d\xde\x0e\x8c\x87\x9e\x52\x96\x39\x7c\xbe\xf8\x52\x47\x6f\xdf"
+ "\x6b\x36\xa9\xb3\xdc\x26\x92\x69\x47\x0f\x68\xcf\x6d\x03\x22\x01\x49\x0f"
+ "\x0d\x36\xa2\xfc\xff\xc9\x8b\xc6\x77\xb9\x51\x94\xaa\xf1\x0f\x79\xdd\xfd"
+ "\x1a\xc0\x4d\x89\xe4\x1d\x6e\x5f\x97\xad\x42\x76\x59\xcb\xa8\x26\x23\x96"
+ "\x5d\xed\xe3\x92\xda\x17\xfe\x3d\x67\xc8\x33\x2a\x7d\x78\x86\xd5\x7c\x75"
+ "\xb2\x29\xb7\x49\x8f\xce\x3c\x73\xbe\x5a\x2c\xe8\x28\x6e\xfd\xdd\x08\x08"
+ "\xc1\x23\x74\x29\x6c\x51\xb9\xe9\x33\x87\x67\x57\x0a\x66\x03\xa2\xa3\x33"
+ "\x85\xc0\xdc\x2f\xea\x71\xe9\xe6\xb1\x37\x39\x13\x10\x72\xc5\x4d\xc5\xc7"
+ "\xad\x1f\x2b\xe6\xdb\x50\xb4\xcc\x2e\x55\xda\x79\xd2\x7d\xaa\x67\x12\xce"
+ "\x0b\xfe\x7e\x9f\x3e\x02\x61\x32\x2b\x1f\xc0\x4a\x0a\x7c\xdd\x2c\x77\xee"
+ "\x47\x16\xb6\xf0\x67\x97\x41\xaf\xa1\xc5\x93\xad\x63\xd8\x28\x06\x4a\x5c"
+ "\xb4\x5f\x5b\xbe\x5d\x98\x02\xb1\x5b\x76\xba\xae\x58\x4f\xeb\x4a\xef\x8e"
+ "\xd7\x23\x87\x96\xc8\x0f\x00\x28\x2b\x5d\xc6\xb6\x31\x80\xe2\xe9\x99\xb6"
+ "\xa9\x7c\x27\xb9\x13\x0d\x3c\xa4\xc2\x32\xc7\x63\xf2\xcc\x1e\x6e\x10\x42"
+ "\xd5\x55\x2c\x15\xf9\x51\x79\x03\x28\x92\xfd\x32\x8a\xff\xcd\xe8\x7a\xd9"
+ "\xb6\xb9\x05\x00\x18\x9b\x47\xff\x1a\x45\xae\xfd\x29\x04\x25\xc2\x42\x94"
+ "\x34\xe5\x48\x46\xee\x09\x21\x0f\xea\x47\x99\x8a\x76\x4e\x51\x34\xf6\x1e"
+ "\x82\x8c\xec\x08\x2b\xfd\x16\x59\xa4\x40\x58\x37\x75\xbf\xcb\x97\x66\x35"
+ "\x1b\x78\x8a\xd7\x4f\x7e\xf0\x7b\x81\x98\x05\x6b\xea\x57\x62\x4b\x30\x2a"
+ "\xed\x67\x14\xbb\xa8\x29\xd3\x6b\x03\x8a\xe0\x8c\xc5\x0b\x0a\x1d\x4b\x9a"
+ "\xb8\x77\x87\x4b\xbd\x56\x62\xc8\x42\x62\xf4\x51\x69\x78\x3b\x59\x21\x60"
+ "\xb8\x5e\x93\x60\x2e\x73\x9a\xed\x9f\xed\x99\x49\x3e\x82\xb9\x82\x7b\xaf"
+ "\x81\x84\x5b\x62\x4c\x4c\xb1\x76\x16\xa0\xe9\x16\x8f\x44\x83\xb4\xdd\xde"
+ "\x48\x16\x61\xf8\xa9\x86\x6f\x2f\x79\x6b\x52\xa5\xe0\xe4\x5e\x7e\x7e\x11"
+ "\xf6\x84\x11\xfe\x6c\x97\xf6\x52\x3c\x70\x30\xe6\x57\x8f\x25\x2f\x17\x47"
+ "\x70\x58\x1d\x92\x35\xf7\xd9\x99\xa4\xcf\x07\x3b\x58\x04\xd3\xa7\x65\xc1"
+ "\x10\x91\x8f\xa7\x78\x79\x56\x71\xcb\x98\x54\xff\x8f\xf5\x9d\xe6\x24\x2a"
+ "\x6b\xff\xc3\x54\x0e\xca\x5f\x94\xb9\x21\x87\xbf\x6f\xd3\x7b\xac\x61\xdd"
+ "\x82\x3a\x98\x82\x9e\xcf\xc4\x74\x7a\x4a\x71\x4f\x0b\xb4\x03\x94\xcc\x00"
+ "\x0a\x96\x68\xb1\xaa\x47\xec\xe9\x4a\xc7\xd0\x20\x22\xdb\x54\xf2\x9b\xc1"
+ "\x21\x69\xe1\x93\x4c\xf2\x35\x66\x78\x17\xe5\xef\x9e\xc4\x5f\x86\xc2\x13"
+ "\xb8\x57\xbe\xd0\x8f\x23\x9d\x1e\x8f\x62\x9e\x7e\x50\xcb\xd7\x16\x5b\x3b"
+ "\xa8\x2d\x62\x57\x33\x30\x7e\xa7\xef\x62\xdd\x0b\x7a\x82\xfd\xc7\x43\x9b"
+ "\x84\x55\x59\x9c\xda\x37\xff\x51\xa5\x0f\xda\x89\x10\x6d\x1f\x67\x36\x71"
+ "\xd8\xb7\xc8\x40\xfd\x4d\x37\x66\x22\x25\xb3\x73\x69\x4c\xc3\x6e\xbf\xe7"
+ "\x43\xde\x04\xff\x86\xef\x1b\x2b\x5a\x85\xc9\x8b\x72\x01\x88\x0b\x75\x3a"
+ "\x22\xad\x26\x30\x18\xe4\xf4\xd8\x65\xa9\x67\x7c\xea\xb4\x0a\x8c\x0c\x9d"
+ "\x9f\xe9\x0e\x19\x32\x9e\xd8\xa6\x18\x5a\x9d\x3a\x36\x47\x04\x73\xd6\x5d"
+ "\xcb\xdb\x1c\xb0\xdf\x94\x22\x27\xff\xf5\x04\xf6\xe0\x04\xce\x97\x2d\xed"
+ "\x4c\xba\x85\xb5\xde\x3e\xe7\x95\x06\xf3\x30\x45\x79\xf2\x0a\xcb\xb9\x92"
+ "\x81\xd1\x30\xa3\xe0\x84\xe9\x3f\x5e\xdc\x3c\x47\x02\x8c\xfb\x34\x34\xbe"
+ "\x18\x4f\xa8\xc1\xc8\xc9\xba\x88\xeb\x1b\xbf\x90\x60\x01\x1f\xbb\xdb\x78"
+ "\x36\xd8\xf7\x9a\x54\x9d\xce\xe1\x48\x09\xfb\xcb\xf0\x92\xbe\xee\x73\xb9"
+ "\xae\xc3\x10\xad\x59\x59\xcc\xa9\x4c\xa2\xa0\xf2\x38\xb8\x66\xc2\xa5\x6a"
+ "\x2b\x0d\xb0\xab\x5b\xfb\x5e\x0d\x20\x15\xf0\x94\x24\x85\x7f\x7d\x99\xb2"
+ "\x8a\x9d\x72\x7c\xdf\x9b\x42\xa4\x41\x20\xb1\x67\xa5\xbc\x12\x26\x5b\x27"
+ "\x95\xc2\x3c\xe4\xb5\x85\x87\xc1\xa3\x7f\x08\x29\x19\x47\xfa\x78\x85\xeb"
+ "\x24\x98\xdf\x6a\x5f\x29\xba\x25\xfd\x9c\x15\xff\xa5\xb2\x60\xa7\x97\xf7"
+ "\x18\xbd\x9e\xad\xe7\x56\xcf\x64\x36\xcc\x39\x1f\xe8\x91\x42\x15\x6d\x38"
+ "\x03\x7d\x71\xf3\xfd\x76\x3d\x27\x52\x5d\x29\x65\xba\xe8\x59\xb2\x93\xb1"
+ "\x78\xe1\xf7\x2e\x26\x9e\x89\xfd\x3e\x6d\x5f\x50\xa3\x4c\x17\x5e\x09\xb4"
+ "\x09\x8b\x94\xc7\xee\x7f\x67\x8d\xa3\xbf\x70\xcb\xdf\x82\xf5\x75\x8b\x5a"
+ "\x0b\xfc\x18\x21\x81\x14\x84\x1c\xf5\x3b\xf2\x48\x84\x8b\xa1\x4b\x02\xac"
+ "\x9d\xa9\xc9\xcf\x65\xfd\x3d\xa4\xa0\x2d\x44\x4b\x90\xbd\x6e\x67\x50\x8c"
+ "\xee\x90\xb5\x8e\x1d\x79\x06\x48\xb6\x22\xee\x27\x54\xe8\xa4\x0c\x52\x38"
+ "\x3f\x53\x80\x21\xbe\xca\xed\x1f\x07\xa2\xc1\xd9\x8c\xbd\xcc\x5e\xef\x48"
+ "\x81\xe6\x35\x2f\xf0\x91\xd8\x58\x0d\x3d\x3c\xc9\xfa\x08\xa6\xc1\xfa\xc8"
+ "\x42\x4a\xa7\xb0\x43\x49\x3f\x34\x81\x2c\x5f\xc6\x1a\xf1\x50\x01\x90\x2b"
+ "\x86\x69\x0c\xeb\x34\x41\x93\xb0\xe8\xf2\xd8\x63\xe9\x10\x4a\x55\x4a\x9b"
+ "\xb9\x7e\x04\xcf\xdd\xb8\xe7\xb3\xff\x31\xb5\x85\xd6\x00\x26\xb4\x2c\xf8"
+ "\xf6\xf0\x23\x56\x36\xc7\x7b\x6f\x91\xdf\x8a\x65\x4b\x1c\x66\x69\x10\x21"
+ "\xf0\xba\xbb\x4f\xe4\xc4\xa4\x24\x58\x02\x6e\x04\x5d\x8a\x63\xb2\xc9\x99"
+ "\x48\x4a\x5f\x9e\xe2\x50\xba\x6b\xde\xbe\xb9\xc9\x9c\x20\x96\x0d\x63\x0a"
+ "\xee\x84\xe0\x63\x85\x6f\xce\x09\x32\x23\x56\xd2\x8d\x5a\x88\xca\x24\x8e"
+ "\x07\xa3\x9e\x7b\x94\x56\xe2\x9b\x3b\x9c\xae\x15\x70\xe1\xbc\x79\xb9\xe9"
+ "\xd5\x30\xcf\x08\x43\x96\xad\x76\x6a\x61\x14\x9a\xa8\x08\x7e\x05\xa3\x4a"
+ "\x8f\x87\x5b\xf8\xee\x71\xd2\x69\x01\x65\x54\xe7\x5a\xf5\x21\x38\x1f\xcf"
+ "\xac\x8b\xab\xb0\x0b\xf3\xaa\x92\x81\xa4\x84\x2c\xad\xca\x00\x4d\xcb\x9f"
+ "\x98\x39\x12\xbf\xcf\x7d\x43\xcf\x49\x00\x13\x5f\x14\x88\x29\x94\xbd\xf4"
+ "\x57\x6b\xb7\x48\x15\x7f\x1a\x90\x7a\x8f\x53\x2c\x5c\x11\xd5\x7a\x19\xbd"
+ "\xf1\x47\x11\xa5\xfd\xe7\x9d\xa8\x7e\xf8\xab\x13\x40\x61\xc3\x9a\xd7\xfe"
+ "\xfc\xc8\xee\x99\x40\xd2\x69\x27\xd9\xdd\xcb\xe4\x9b\x08\xa5\x16\xb8\x86"
+ "\x56\x1c\xef\x41\x3f\xac\xa7\x24\x4e\x0e\xcc\xaf\x1a\xac\x80\xa0\xa6\x2e"
+ "\x3f\x77\xc0\x8c\x5d\x3c\x31\xad\x33\x9d\x7c\xa2\x84\x5a\x35\x1a\xb4\x2b"
+ "\xda\x33\xda\x18\x5b\x40\x17\xdf\x44\xe3\xe8\x34\xef\xce\xd5\x7f\xc2\xee"
+ "\x7d\xe6\x80\xe2\x0b\xe3\xe6\x96\xc8\x9a\x2a\x6c\x58\xc1\x3d\x42\xb6\xba"
+ "\x07\xdf\x02\x38\xc4\xb7\x1a\xd4\x56\x62\x13\xcb\xbc\x1d\xc8\x6d\x37\xbd"
+ "\x0b\x96\x42\x94\xed\x00\x90\x1b\x09\x20\x2d\x83\x29\xe5\xd6\x4d\xcb\xf1"
+ "\x08\xc1\x18\x0e\x9a\xd1\xf8\xa9\xf4\x4e\x87\xcc\xd5\xe1\x70\x00\xd6\x68"
+ "\x65\x66\x33\x49\xc4\x50\xe3\x3a\x12\xf5\xc2\x96\xc4\x44\xd8\xad\xc5\x71"
+ "\xfe\x40\xaa\x78\xaf\xd8\x31\x5d\xdd\xa8\xef\xef\x4c\x39\x32\x88\x73\xde"
+ "\x2f\x5e\x70\x8c\x24\x71\xf8\x93\x23\x33\x10\x99\x5c\x6d\xa4\xf9\xa2\x08"
+ "\x8f\xee\x34\xe2\x58\xe5\xcf\xf4\x85\xec\xa7\xef\xdc\x87\xaa\x1e\xbd\xfd"
+ "\xc3\x09\xc6\xeb\x97\x3b\x24\x8a\x65\x9c\x81\xdc\xb1\x8b\x40\x0b\xb7\x4f"
+ "\x32\x47\xf2\x96\xd8\x17\x99\xb9\xcc\x31\xee\x84\x43\x5d\xb7\xf0\xd8\xc3"
+ "\xfa\x81\x4b\x94\x06\x82\x71\xdc\x6a\x93\x1d\x0a\x52\xb6\x10\x58\x82\x45"
+ "\xaf\x5c\x1b\xf2\x04\xe0\xe1\xc5\x5e\x0b\x72\xdb\x89\x69\x8d\x65\xd8\x0b"
+ "\x13\xf6\x2a\xf6\x49\x33\x8c\xcf\x6a\x15\x8b\x9e\x9a\xba\x3f\xd0\x3b\x9e"
+ "\x19\xad\x76\xf6\x9a\xaf\xb4\xb1\x25\xd6\xba\x86\xd6\xbc\xf5\x04\x7c\xf3"
+ "\xe4\xa2\x4a\xe1\xd6\x9c\xf2\xe7\xfe\xe3\x3e\x34\x2c\x69\x1a\x24\xfd\xc5"
+ "\x11\x9b\x47\x8b\x24\xbd\xac\x06\xeb\x8d\x58\xc2\x62\x6d\xb6\x00\x71\x81"
+ "\x8b\xf5\xef\x89\x0b\x61\xfe\xdf\xa9\x6a\xd6\xe7\x8d\x99\x35\xc8\x09\xfc"
+ "\xae\xcb\x6e\xf4\x89\x1b\xf8\xd7\x10\xdb\x70\x53\xbb\xe7\x01\x2d\xb4\xb3"
+ "\x05\xb3\xa5\x08\xf2\xcd\x94\x71\xd2\x1e\x5e\x21\x46\x7e\xbc\xf9\x37\xa6"
+ "\xc7\x52\xd8\xf6\x46\xbe\xaf\x0f\x6c\x4a\xa4\x23\x16\xb2\x51\x80\x93\xbc"
+ "\x71\x69\x96\x56\x43\x19\x7d\x0c\x62\x95\x0f\xa7\x41\x37\x3a\xac\xd7\x14"
+ "\xd8\x2d\x4a\x0d\x1d\x2a\x55\xc1\x91\x8f\xa0\x86\x3d\xff\x1e\x3d\xd1\x2a"
+ "\x68\x70\x11\xc1\x12\x8b\xb5\xe6\x3f\x58\xbe\xaa\x7b\xaf\x92\x7a\x03\x3f"
+ "\x75\xa0\x99\xfe\xa6\x75\x00\x08\x1d\xe1\x03\x1f\x85\x56\x0c\x81\x93\x84"
+ "\xa1\x64\xc6\x9c\xa8\x07\x30\x81\x1f\x17\xbf\x70\x7c\x7d\x0c\x9f\x56\xa6"
+ "\x61\xab\x2d\xfc\xe6\xa0\x7c\x61\x77\x92\x15\x89\x63\xca\x96\xfd\x67\x1b"
+ "\x4c\x2d\xd7\x30\x00\x9f\x1e\xb1\xab\xe1\x12\x2a\xaa\x0b\x15\x9c\x29\x5d"
+ "\xe2\x1b\xda\x5d\xf6\x3e\x56\x5e\xbc\xb6\x64\x27\x0a\xe3\x0a\x52\x03\x55"
+ "\x50\x55\x2e\x94\x3d\xca\x22\xf6\xc0\x89\x2c\x3e\x93\xab\xcd\xe8\x61\xf2"
+ "\xec\x19\x9b\x63\x9a\xf6\xf5\x16\xfd\xb5\x81\xd5\xe2\x3b\xfc\x1b\x03\x5b"
+ "\xf7\x67\xec\xea\x78\x12\x6f\xbf\xc6\x51\x1c\xa4\x13\xae\xdf\x51\xae\xf6"
+ "\xac\x19\xa5\xda\x04\xbc\x38\x26\x0e\x7f\x7f\x4f\x99\x16\x5f\x4e\x26\x92"
+ "\x05\x3a\xaa\xe1\x68\xeb\x96\x0d\x76\x2d\xf1\xc5\x06\x4b\x87\x96\xff\x5c"
+ "\x6d\xcc\x93\x4a\x96\x8d\x3c\xe2\x9b\x6a\xf0\x95\x0d\xdc\x07\xc7\x60\xc7"
+ "\xdc\x1e\x3d\x90\xec\x02\x63\x9e\x80\xed\x51\x23\x04\xab\x03\x18\xea\x16"
+ "\x38\xad\x91\xc8\xcb\xa9\x22\xff\x36\x45\x79\x99\x52\x1a\x3e\x84\xcc\x27"
+ "\xac\x68\x2f\xe1\x4e\x78\x91\x46\x0f\x2c\x0e\x5c\x80\xa9\x48\x56\x0e\xb8"
+ "\x0e\xc9\xd3\x5d\xbe\x98\x8d\xe8\x6d\x25\xe7\x16\xc1\x24\x11\xaf\xf9\x56"
+ "\xcb\xe6\x79\x88\x95\x5b\x95\x6a\xb9\xd8\xb5\xe2\x52\x01\x5f\x30\xce\xbc"
+ "\x59\xc4\xe1\x7f\x0d\xb5\x8c\xf5\x40\x62\x09\x92\xf6\xee\xce\xec\x0a\x30"
+ "\x10\x4f\x39\x85\xde\x3d\x95\x42\x0d\x21\x5a\x19\x9a\xa4\x78\x97\xad\xee"
+ "\xe2\x36\x10\xd2\x1a\x7f\x20\xdc\x27\xc8\xd0\x69\xdf\xd6\x33\x71\xf6\xac"
+ "\xd8\x4e\xe7\x48\xb7\x5b\x39\xa8\xc9\x96\x6a\x74\x05\x96\x6f\xfd\x79\xe3"
+ "\x69\x9c\x0f\x1c\x87\x1d\x19\x81\x28\xda\xe7\x99\x4d\x26\xbf\xde\x40\xd4"
+ "\x6a\xd2\xcf\x56\xad\xb9\x6e\xec\xad\x05\x6f\x80\xfa\x31\x31\xfd\x2d\x00"
+ "\xfc\xe5\x21\x55\x72\x5e\xc5\x02\x7c\xfd\x24\x9e\x5d\x30\x9a\x3e\xa5\x29"
+ "\x85\x3b\xc6\x17\x2e\x31\x78\x9e\x77\x78\xf6\x49\x1d\x98\xfd\x10\x0c\xf9"
+ "\xfe\xda\x43\x2a\x10\x64\x67\x3f\xa7\x8c\x12\xf2\x20\xd6\x67\x50\x2d\x5e"
+ "\x32\xf2\x43\x6b\xaf\xd2\x7e\xc2\xf7\x57\x07\x99\x2f\x01\x30\x54\x67\x2c"
+ "\x85\x0d\xce\xc8\xab\x96\x53\x4f\x70\x1a\x9e\xf2\x6e\xdd\x19\xf4\x35\x0e"
+ "\x7a\xe9\xf5\xe1\x18\x68\xaf\x59\x43\x57\xc8\x3f\x41\x28\x65\xc1\x0f\xc7"
+ "\x9f\xc4\xfe\xbd\x43\xa0\x35\x09\x5f\x93\x74\xc4\xe0\x14\x10\x26\xb1\x3a"
+ "\x24\xa2\x2a\xe1\xe7\x32\x7e\x05\x16\x4a\xe2\xa5\xcc\xae\x68\x99\x1b\x57"
+ "\x6e\xa8\x65\x38\x30\x1e\xac\xab\x0d\xe7\xeb\x4c\x95\x27\x4b\xe9\x58\xa3"
+ "\x49\x4b\xc8\xbb\x5a\xf0\x27\x4e\xed\xc6\xa1\x18\x77\xe1\xc0\x40\xfc\xeb"
+ "\x17\x5f\xf2\xa1\xde\xda\x0b\x1c\x3c\xb4\x7f\xdf\x4b\xc3\x8a\xac\x66\x8b"
+ "\x23\x62\xd5\x22\x8e\xcf\x7c\x95\x2e\xb2\x57\x2a\x07\x46\x09\x78\xd5\xd9"
+ "\xe6\xf7\xb4\xf5\x2f\xea\x67\x3d\xb2\x46\x29\x5d\x1b\x0c\xd9\xcc\x33\x17"
+ "\x04\xaa\x64\x89\xb4\xce\x8c\x03\x9b\x25\x20\x7e\x80\x49\x44\x7a\x22\xa5"
+ "\x7e\xbc\x35\xe1\x65\xe4\xe0\x10\x83\x04\xea\x14\x21\xbc\xae\xd2\x61\x32"
+ "\x9d\x4c\xb2\xa7\xc7\x34\x80\x1d\x69\xdb\x9e\xa5\x5a\x07\xba\x37\x8e\x90"
+ "\x7c\xfb\x87\x42\xf1\x2b\x3f\x38\x15\x83\xf1\x7a\xce\x46\x9f\x4c\x2d\x3a"
+ "\xdb\x2f\xf0\xbe\x64\x6f\x69\xa4\x0f\x35\x27\x08\x7e\xff\x0c\xbc\x3a\x02"
+ "\x46\x22\x74\x30\xa7\xc5\x41\x91\x0d\x7b\xde\xfb\xb3\xff\x00\x1b\xeb\xa9"
+ "\x67\xd6\xeb\x4b\x5f\xeb\x6c\xbf\x44\x33\xa1\x1f\x11\x4b\x0b\x13\xb7\x1d"
+ "\xb1\x6e\x35\x88\x68\x74\x30\xb2\x7e\x0e",
+ 4096);
+ *(uint16_t*)0x20001304 = 0x1000;
+ syscall(__NR_write, r[0], 0x20000300ul, 0x1006ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0c641fb581d08c1ef69b061b6517c41c180e99d1.c b/syzkaller-repros/linux/0c641fb581d08c1ef69b061b6517c41c180e99d1.c
new file mode 100644
index 0000000..859f575
--- /dev/null
+++ b/syzkaller-repros/linux/0c641fb581d08c1ef69b061b6517c41c180e99d1.c
@@ -0,0 +1,311 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0x0};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 2ul, 0x4000000805ul, 0);
+ if (res != -1)
+ r[0] = res;
+ res = syscall(__NR_socket, 2ul, 5ul, 0x84ul);
+ if (res != -1)
+ r[1] = res;
+ res = syscall(__NR_dup3, r[0], r[1], 0ul);
+ if (res != -1)
+ r[2] = res;
+ *(uint16_t*)0x20d6cff0 = 2;
+ *(uint16_t*)0x20d6cff2 = htobe16(0x4e20);
+ *(uint32_t*)0x20d6cff4 = htobe32(0x7f000001);
+ syscall(__NR_setsockopt, r[1], 0x84ul, 0x64ul, 0x20d6cff0ul, 0x10ul);
+ memcpy((void*)0x20fa3fff, "\t", 1);
+ *(uint16_t*)0x206f7000 = 2;
+ *(uint16_t*)0x206f7002 = htobe16(0);
+ *(uint8_t*)0x206f7004 = 0xac;
+ *(uint8_t*)0x206f7005 = 0x14;
+ *(uint8_t*)0x206f7006 = -1;
+ *(uint8_t*)0x206f7007 = 0xbb;
+ syscall(__NR_sendto, r[2], 0x20fa3ffful, 1ul, 0ul, 0x206f7000ul, 0x10ul);
+ memcpy((void*)0x203cef9f, "7", 1);
+ *(uint16_t*)0x20618000 = 2;
+ *(uint16_t*)0x20618002 = htobe16(0x4e20);
+ *(uint32_t*)0x20618004 = htobe32(0x7f000001);
+ syscall(__NR_sendto, r[1], 0x203cef9ful, 0x10231ul, 0ul, 0x20618000ul,
+ 0x10ul);
+ memcpy((void*)0x2025e000, "\x7f\x00\x00\x00", 4);
+ *(uint32_t*)0x2025e004 = 0;
+ *(uint32_t*)0x2025e008 = 0;
+ *(uint32_t*)0x20a8a000 = 0xc;
+ res = syscall(__NR_getsockopt, r[1], 0x84ul, 0x1dul, 0x2025e000ul,
+ 0x20a8a000ul);
+ if (res != -1)
+ r[3] = *(uint32_t*)0x2025e008;
+ *(uint32_t*)0x2059aff8 = r[3];
+ *(uint32_t*)0x2059affc = 0;
+ *(uint32_t*)0x2034f000 = 0x2059b000;
+ syscall(__NR_getsockopt, r[2], 0x84ul, 0x7aul, 0x2059aff8ul, 0x2034f000ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0d68c5a10991af67c5857fb25a9d33a5f75c69c5.c b/syzkaller-repros/linux/0d68c5a10991af67c5857fb25a9d33a5f75c69c5.c
new file mode 100644
index 0000000..bda548b
--- /dev/null
+++ b/syzkaller-repros/linux/0d68c5a10991af67c5857fb25a9d33a5f75c69c5.c
@@ -0,0 +1,95 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+const int kFailStatus = 67;
+const int kRetryStatus = 69;
+
+__attribute__((noreturn)) static void doexit(int status)
+{
+ volatile unsigned i;
+ syscall(__NR_exit_group, status);
+ for (i = 0;; i++) {
+ }
+}
+
+__attribute__((noreturn)) static void fail(const char* msg, ...)
+{
+ int e = errno;
+ fflush(stdout);
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, " (errno %d)\n", e);
+ doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
+}
+
+static void use_temporary_dir()
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ fail("failed to mkdtemp");
+ if (chmod(tmpdir, 0777))
+ fail("failed to chmod");
+ if (chdir(tmpdir))
+ fail("failed to chdir");
+}
+
+long r[29];
+void loop()
+{
+ memset(r, -1, sizeof(r));
+ r[0] = syscall(__NR_mmap, 0x20000000ul, 0xfff000ul, 0x3ul, 0x32ul,
+ 0xfffffffffffffffful, 0x0ul);
+ *(uint32_t*)0x20851000 = (uint32_t)0x1;
+ *(uint32_t*)0x20851004 = (uint32_t)0x3;
+ *(uint64_t*)0x20851008 = (uint64_t)0x201abfe8;
+ *(uint64_t*)0x20851010 = (uint64_t)0x20b4d000;
+ *(uint32_t*)0x20851018 = (uint32_t)0x1;
+ *(uint32_t*)0x2085101c = (uint32_t)0x80;
+ *(uint64_t*)0x20851020 = (uint64_t)0x2000a000;
+ *(uint32_t*)0x20851028 = (uint32_t)0x0;
+ *(uint32_t*)0x2085102c = (uint32_t)0x0;
+ *(uint8_t*)0x201abfe8 = (uint8_t)0x8db7;
+ *(uint8_t*)0x201abfe9 = (uint8_t)0x0;
+ *(uint16_t*)0x201abfea = (uint16_t)0x0;
+ *(uint32_t*)0x201abfec = (uint32_t)0xe70;
+ *(uint8_t*)0x201abff0 = (uint8_t)0x20000007;
+ *(uint8_t*)0x201abff1 = (uint8_t)0x80000001;
+ *(uint16_t*)0x201abff2 = (uint16_t)0x0;
+ *(uint32_t*)0x201abff4 = (uint32_t)0xffffffffffffffff;
+ *(uint8_t*)0x201abff8 = (uint8_t)0xd395;
+ *(uint8_t*)0x201abff9 = (uint8_t)0x0;
+ *(uint16_t*)0x201abffa = (uint16_t)0x0;
+ *(uint32_t*)0x201abffc = (uint32_t)0x0;
+ memcpy((void*)0x20b4d000, "\x73\x79\x73\x65\x4f\x00", 6);
+ r[23] = syscall(__NR_bpf, 0x5ul, 0x20851000ul, 0x30ul);
+ r[24] = syscall(__NR_socket, 0x29ul, 0x2ul, 0x0ul);
+ r[25] = syscall(__NR_socket, 0x29ul, 0x5ul, 0x0ul);
+ *(uint32_t*)0x20cb6ff8 = r[25];
+ *(uint32_t*)0x20cb6ffc = r[23];
+ r[28] = syscall(__NR_ioctl, r[24], 0x89e0ul, 0x20cb6ff8ul);
+}
+
+int main()
+{
+ use_temporary_dir();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0ecb8544c47bb7d668a1951ff5ff4c38c5a32f24.c b/syzkaller-repros/linux/0ecb8544c47bb7d668a1951ff5ff4c38c5a32f24.c
new file mode 100644
index 0000000..6f4190b
--- /dev/null
+++ b/syzkaller-repros/linux/0ecb8544c47bb7d668a1951ff5ff4c38c5a32f24.c
@@ -0,0 +1,1203 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+ if (res != -1)
+ r[0] = res;
+ NONFAILING(*(uint64_t*)0x200031c0 = 0);
+ NONFAILING(*(uint32_t*)0x200031c8 = 0);
+ NONFAILING(*(uint64_t*)0x200031d0 = 0x20003180);
+ NONFAILING(*(uint64_t*)0x20003180 = 0x20000000);
+ NONFAILING(*(uint32_t*)0x20000000 = 0x38);
+ NONFAILING(*(uint16_t*)0x20000004 = 0x1403);
+ NONFAILING(*(uint16_t*)0x20000006 = 1);
+ NONFAILING(*(uint32_t*)0x20000008 = 0);
+ NONFAILING(*(uint32_t*)0x2000000c = 0);
+ NONFAILING(*(uint16_t*)0x20000010 = 9);
+ NONFAILING(*(uint16_t*)0x20000012 = 2);
+ NONFAILING(memcpy((void*)0x20000014, "syz1\000", 5));
+ NONFAILING(*(uint16_t*)0x2000001c = 8);
+ NONFAILING(*(uint16_t*)0x2000001e = 0x41);
+ NONFAILING(memcpy((void*)0x20000020, "siw\000", 4));
+ NONFAILING(*(uint16_t*)0x20000024 = 0x14);
+ NONFAILING(*(uint16_t*)0x20000026 = 0x33);
+ NONFAILING(
+ memcpy((void*)0x20000028,
+ "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint64_t*)0x20003188 = 0x38);
+ NONFAILING(*(uint64_t*)0x200031d8 = 1);
+ NONFAILING(*(uint64_t*)0x200031e0 = 0);
+ NONFAILING(*(uint64_t*)0x200031e8 = 0);
+ NONFAILING(*(uint32_t*)0x200031f0 = 0);
+ inject_fault(4);
+ syscall(__NR_sendmsg, r[0], 0x200031c0ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ install_segv_handler();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0f798bd6908a49a54cb972b2b92241e5783c6421.c b/syzkaller-repros/linux/0f798bd6908a49a54cb972b2b92241e5783c6421.c
new file mode 100644
index 0000000..c5796c6
--- /dev/null
+++ b/syzkaller-repros/linux/0f798bd6908a49a54cb972b2b92241e5783c6421.c
@@ -0,0 +1,454 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+void execute_one(void)
+{
+ *(uint8_t*)0x20000000 = 0x12;
+ *(uint8_t*)0x20000001 = 1;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint8_t*)0x20000004 = 0x58;
+ *(uint8_t*)0x20000005 = 0x7e;
+ *(uint8_t*)0x20000006 = 0xc7;
+ *(uint8_t*)0x20000007 = 8;
+ *(uint16_t*)0x20000008 = 0x841;
+ *(uint16_t*)0x2000000a = 1;
+ *(uint16_t*)0x2000000c = 0xed74;
+ *(uint8_t*)0x2000000e = 0;
+ *(uint8_t*)0x2000000f = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 1;
+ *(uint8_t*)0x20000012 = 9;
+ *(uint8_t*)0x20000013 = 2;
+ *(uint16_t*)0x20000014 = 0x12;
+ *(uint8_t*)0x20000016 = 1;
+ *(uint8_t*)0x20000017 = 0;
+ *(uint8_t*)0x20000018 = 0;
+ *(uint8_t*)0x20000019 = 0;
+ *(uint8_t*)0x2000001a = 0;
+ *(uint8_t*)0x2000001b = 9;
+ *(uint8_t*)0x2000001c = 4;
+ *(uint8_t*)0x2000001d = 0x6e;
+ *(uint8_t*)0x2000001e = 0;
+ *(uint8_t*)0x2000001f = 0;
+ *(uint8_t*)0x20000020 = 0xe5;
+ *(uint8_t*)0x20000021 = 0xb7;
+ *(uint8_t*)0x20000022 = -1;
+ *(uint8_t*)0x20000023 = 0;
+ syz_usb_connect(5, 0x24, 0x20000000, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/0fac2c3f760499a1802232af55857850a18713c0.c b/syzkaller-repros/linux/0fac2c3f760499a1802232af55857850a18713c0.c
new file mode 100644
index 0000000..c6bb798
--- /dev/null
+++ b/syzkaller-repros/linux/0fac2c3f760499a1802232af55857850a18713c0.c
@@ -0,0 +1,400 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 12; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0x0,
+ 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0xaul, 5ul, 0x84ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_shutdown, r[0], 0ul);
+ break;
+ case 2:
+ *(uint32_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000004 = 0x1c;
+ *(uint64_t*)0x20000008 = 0x20000080;
+ *(uint16_t*)0x20000080 = 0xa;
+ *(uint16_t*)0x20000082 = htobe16(0);
+ *(uint32_t*)0x20000084 = htobe32(0);
+ memcpy((void*)0x20000088,
+ "\xfd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x20000180 = 0x10;
+ syscall(__NR_getsockopt, r[0], 0x84ul, 0x6ful, 0x20000000ul, 0x20000180ul);
+ break;
+ case 3:
+ res = syscall(__NR_socket, 2ul, 0x80001ul, 0x84);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 4:
+ *(uint32_t*)0x20000040 = 8;
+ res = syscall(__NR_getsockopt, r[1], 0x84ul, 0x14ul, 0x20000000ul,
+ 0x20000040ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000000;
+ break;
+ case 5:
+ *(uint32_t*)0x200000c0 = r[2];
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ syscall(__NR_setsockopt, -1, 0x84ul, 0ul, 0x200000c0ul, 0x10ul);
+ break;
+ case 6:
+ *(uint16_t*)0x20000000 = 0xa;
+ *(uint16_t*)0x20000002 = htobe16(0);
+ *(uint32_t*)0x20000004 = htobe32(0);
+ *(uint8_t*)0x20000008 = 0xfe;
+ *(uint8_t*)0x20000009 = 0x88;
+ *(uint8_t*)0x2000000a = 0;
+ *(uint8_t*)0x2000000b = 0;
+ *(uint8_t*)0x2000000c = 0;
+ *(uint8_t*)0x2000000d = 0;
+ *(uint8_t*)0x2000000e = 0;
+ *(uint8_t*)0x2000000f = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 0;
+ *(uint8_t*)0x20000012 = 0;
+ *(uint8_t*)0x20000013 = 0;
+ *(uint8_t*)0x20000014 = 0;
+ *(uint8_t*)0x20000015 = 0;
+ *(uint8_t*)0x20000016 = 0;
+ *(uint8_t*)0x20000017 = 1;
+ *(uint32_t*)0x20000018 = 0;
+ *(uint16_t*)0x2000001c = 0xa;
+ *(uint16_t*)0x2000001e = htobe16(0);
+ *(uint32_t*)0x20000020 = htobe32(0);
+ *(uint8_t*)0x20000024 = -1;
+ *(uint8_t*)0x20000025 = 2;
+ *(uint8_t*)0x20000026 = 0;
+ *(uint8_t*)0x20000027 = 0;
+ *(uint8_t*)0x20000028 = 0;
+ *(uint8_t*)0x20000029 = 0;
+ *(uint8_t*)0x2000002a = 0;
+ *(uint8_t*)0x2000002b = 0;
+ *(uint8_t*)0x2000002c = 0;
+ *(uint8_t*)0x2000002d = 0;
+ *(uint8_t*)0x2000002e = 0;
+ *(uint8_t*)0x2000002f = 0;
+ *(uint8_t*)0x20000030 = 0;
+ *(uint8_t*)0x20000031 = 0;
+ *(uint8_t*)0x20000032 = 0;
+ *(uint8_t*)0x20000033 = 1;
+ *(uint32_t*)0x20000034 = 0;
+ *(uint16_t*)0x20000038 = 2;
+ *(uint32_t*)0x2000003c = 0;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0;
+ syscall(__NR_setsockopt, -1, 0x29ul, 0xccul, 0x20000000ul, 0x5cul);
+ break;
+ case 7:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 6);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 8:
+ memcpy((void*)0x20000000,
+ "\x1b\xa0\x00\x00\x19\x00\x1d\x0d\x89\xfd\xc5\xcb\xdd\x04\x57\x98"
+ "\x70\x7b\xed\x4d\xca\x14\xa7\x96\x0f\x0f\x8e\xc8\xda\x78\x03\x1c"
+ "\x76\x60\xb0\x8f\x51\x5e",
+ 38);
+ syscall(__NR_sendto, r[3], 0x20000000ul, 0xff3bul, 0ul, 0ul, 0x2e2ul);
+ break;
+ case 9:
+ memcpy((void*)0x20000080,
+ "\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x01\x00\x05\x02\x00\x00\x00"
+ "\x01\x00\x07\x10\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x01\x00\x00\x04\xba\x05\xc9\x10\xfe\x88\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x15",
+ 59);
+ syscall(__NR_setsockopt, -1, 0x29ul, 0ul, 0x20000080ul, 1ul);
+ break;
+ case 10:
+ syscall(__NR_getsockopt, -1, 0x84ul, 0x6ful, 0ul, 0ul);
+ break;
+ case 11:
+ syscall(__NR_recvfrom, -1, 0ul, 0ul, 0x700ul, 0ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/10681a527a04da4b77753f36780b87143714d47d.c b/syzkaller-repros/linux/10681a527a04da4b77753f36780b87143714d47d.c
new file mode 100644
index 0000000..b881c5d
--- /dev/null
+++ b/syzkaller-repros/linux/10681a527a04da4b77753f36780b87143714d47d.c
@@ -0,0 +1,226 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint64_t*)0x20000250 = 0x20000200;
+ *(uint64_t*)0x20000200 = 0x200001c0;
+ *(uint32_t*)0x200001c0 = 0x1c;
+ *(uint8_t*)0x200001c4 = 7;
+ *(uint8_t*)0x200001c5 = 6;
+ *(uint16_t*)0x200001c6 = 0x801;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint32_t*)0x200001cc = 0;
+ *(uint8_t*)0x200001d0 = 0;
+ *(uint8_t*)0x200001d1 = 0;
+ *(uint16_t*)0x200001d2 = htobe16(0);
+ *(uint16_t*)0x200001d4 = 5;
+ *(uint16_t*)0x200001d6 = 1;
+ *(uint8_t*)0x200001d8 = 7;
+ *(uint64_t*)0x20000208 = 0x1c;
+ *(uint64_t*)0x20000258 = 1;
+ *(uint64_t*)0x20000260 = 0;
+ *(uint64_t*)0x20000268 = 0;
+ *(uint32_t*)0x20000270 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000240ul, 0ul);
+ syscall(__NR_recvfrom, -1, 0ul, 0ul, 0xf00ul, 0ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0x4000000;
+ *(uint64_t*)0x20000150 = 0x20000100;
+ *(uint64_t*)0x20000100 = 0x20000040;
+ *(uint32_t*)0x20000040 = 0x5c;
+ *(uint8_t*)0x20000044 = 2;
+ *(uint8_t*)0x20000045 = 6;
+ *(uint16_t*)0x20000046 = 0x101;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint8_t*)0x20000050 = 0;
+ *(uint8_t*)0x20000051 = 0;
+ *(uint16_t*)0x20000052 = htobe16(0);
+ *(uint16_t*)0x20000054 = 5;
+ *(uint16_t*)0x20000056 = 1;
+ *(uint8_t*)0x20000058 = 7;
+ *(uint16_t*)0x2000005c = 5;
+ *(uint16_t*)0x2000005e = 4;
+ *(uint8_t*)0x20000060 = 0;
+ *(uint16_t*)0x20000064 = 0x10;
+ *(uint16_t*)0x20000066 = 3;
+ memcpy((void*)0x20000068, "bitmap:port\000", 12);
+ *(uint16_t*)0x20000074 = 0x14;
+ STORE_BY_BITMASK(uint16_t, , 0x20000076, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000077, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000077, 1, 7, 1);
+ *(uint16_t*)0x20000078 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x2000007a, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000007b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000007b, 0, 7, 1);
+ *(uint16_t*)0x2000007c = htobe16(0);
+ *(uint16_t*)0x20000080 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x20000082, 4, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000083, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000083, 0, 7, 1);
+ *(uint16_t*)0x20000084 = htobe16(0);
+ *(uint16_t*)0x20000088 = 9;
+ *(uint16_t*)0x2000008a = 2;
+ memcpy((void*)0x2000008c, "syz0\000", 5);
+ *(uint16_t*)0x20000094 = 5;
+ *(uint16_t*)0x20000096 = 5;
+ *(uint8_t*)0x20000098 = 0;
+ *(uint64_t*)0x20000108 = 0x5c;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000140ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/107f9ebfce2c1a2ab0331b58ca2f8608b25436c2.c b/syzkaller-repros/linux/107f9ebfce2c1a2ab0331b58ca2f8608b25436c2.c
new file mode 100644
index 0000000..e5d4018
--- /dev/null
+++ b/syzkaller-repros/linux/107f9ebfce2c1a2ab0331b58ca2f8608b25436c2.c
@@ -0,0 +1,544 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000300, "/dev/kvm\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000300ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ res = syscall(__NR_ioctl, r[0], 0xae01ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_ioctl, r[1], 0xae60ul, 0);
+ res = syscall(__NR_ioctl, r[1], 0xae41ul, 0x1000000000000102ul);
+ if (res != -1)
+ r[2] = res;
+ memcpy(
+ (void*)0x200004c0,
+ "\x6c\x64\x12\x5f\xa9\x6f\xa4\x2b\x76\x1c\x6e\xc2\x5b\x2b\xec\x0b\xa4\xc8"
+ "\x10\x36\xc9\x3a\x40\xc8\xa4\xd4\x41\x2a\x76\x3b\x00\x04\x00\x00\x00\x00"
+ "\x00\x00\x3c\x5c\xa2\x06\xc0\x47\xec\xee\x37\x7a\xba\xec\xe6\xb8\x83\x78"
+ "\xe3\xd6\x3a\x98\xfc\x19\x1f\x36\x1d\x26\x4f\xfa\x8b\x46\x48\x5f\x02\xba"
+ "\xee\x1a\xb6\xb8\x15\x42\x52\x06\x61\x78\x86\x8d\x1e\xf4\xa8\x36\x5c\x5d"
+ "\xc2\x6c\xa0\x97\xdd\xda\x7c\x21\xa9\x84\xc2\xb9\xca\x4b\xbb\x7a\x87\x16"
+ "\x5c\x0c\x1d\xbc\x75\xd7\xea\x4d\xf1\x00\x10\x17\x4a\x3a\xc8\x69\x45\x25"
+ "\x95\x2f\x44\x50\x0a\x1f\x0d\xb5\x09\xc3\x2c\xc7\xac\xe8\x42\xc2\x8f\x37"
+ "\xf0\x6e\x4e\xa9\xf1\xe5\xf0\xc6\xc3\x79\xf9\xcc\x58\xbf\x69\xfc\xde\x31"
+ "\x8e\xad\x48\x25\xaa\x1b\x6a\x83\x2d\x4e\x48\xcc\x41\xbb\x5a\x6b\xaa\x41"
+ "\xd6\x14\xf6\xc8\x94\x1b\xee\x80\x59\x54\xa6\x2d\x19\x6a\x07\x00\x00\x00"
+ "\xb2\x12\x24\xb5\x7f\x53\x0d\x00\x00\xc1\xff\x53\xbf\x79\xa1\xf5\xc5\xdc"
+ "\x34\xb2\x26\x2d\x66\xae\x79\x3b\x63\x04\xa3\x0b\x97\x07\x7f\x1c\x13\x10"
+ "\x45\xcb\xc1\x1c\x45\x62\xd2\x2d\xb8\x8d\x0e\xdc\x5d\xae\xe1\x71\xcc\x04"
+ "\xd9\x6d\x9e\xc2\xdb\x07\x47\x8f\x34\x7e\xdb\xd6\x40\x49\x23\xad\x4a\x56"
+ "\x72\xb1\xb2\x85\xc7\x98\x8c\x4e\xc0\x92\x2c\x65\x5f\xf6\x00\x00\x00\x00"
+ "\xc0\x0d\xc2\x90\xd9\x36\xd9\x32\x36\x05\x1f\xad\xfb\x4b\x95\xd0\x2c\x0b"
+ "\xda\x7c\xe3\x8d\xab\xb7\xcd\x10\x3f\xe4\xd0\xc9\xc9\x63\xcd\x71\x7a\x77"
+ "\xf8\xdf\x8d\x46\x09\x9b\x1f\x58\xe0\x68\xaf\x6a\xfb\xbc\x19\xdb\x16\x1c"
+ "\x6d\xf3\xe7\xc9\xc7\x1b\xc0\x8a\x28\x2f\xc2\xc1\x42\x85\x6b\x5e\x4c\xaf"
+ "\xf4\xc0\xa4\xf7\x24\x45\xef\x10\xdc\xd2\xc5\x69\x31\x9d\x6e\x9b\xb2\x05"
+ "\x8d\x02\x3f\x66\x9a\x64\xfc\x7d\x96\x84\xb4\x5b\x00\x00\x00\x00\x36\x46"
+ "\x73\xdc\xfa\x92\x35\xea\x5a\x2f\xf2\x3c\x4b\xb5\xc5\xac\xb2\x90\xe8\x97"
+ "\x6d\xca\xc7\x79\xff\x00\x27\xb4\x87\x34\x2b\x9e\x21\x26\x18\x5a\xfe\x28"
+ "\xa7\x74\xb9\x9d\x38\x90\xbd\x37\x42\x86\x17\xde\x4c\xdd\x6f\x53\xc4\x19"
+ "\xce\x31\x05\x41\x82\xfd\x09\x8a\xf7\xb7\xf1\xb1\x15\x2c\x69\x16\x11\xf8"
+ "\x97\x55\x8d\x4b\x75\x5c\xb7\x83\x97\x8d\x98\x59\xb0\x53\x7b\x05\xb6\x23"
+ "\xdc\xb5\xc4\xca\x93\x17\x47\x1a\x40\xfa\x49\x98\xcc\xa8\x0e\x96\x1e\xff"
+ "\xfb\x4e\x1a\xa2\x5d\x8a\x17\xde\xef\x0c\x86\x94\xc4\x39\x5f\xc9\x9b\xe3"
+ "\xc3\xfe\x7a\xeb\x8a\xf4\x92\x9c\xe7\xd3\x46\xca\x62\xb2\x5d\x48\xfd\xa5"
+ "\xd1\x01\x46\x70\x2f\x78\xb2\x33\xb5\x20\x87\x52\x72\x6e\xd9\xf0\xc3\x40"
+ "\xd4\x94\xb9\x2d\x19\xcc\x93\x0b\xb8\xa5\xf8\xb4\xda\x8f\x46\x03\xac\x0c"
+ "\x3b\x69\x83\x84\xe1\x7a\x57\x0d\xc8\x52\x48\x23\xed\x15\xaf\x4e\xcf\xab"
+ "\xb4\xb2\x54\x1d\x3c\x11\x4b\x7b\xba\x1c\x21\xa8\x45\xc9\xcf\x0d\x1c\xc2"
+ "\x4a\xba\x47\xe3\x0f\x55\x8b\x22\x46\xad\x95\xcc\xf7\xd2\xf8\x0c\xc0\xab"
+ "\x26\xf0\x83\x36\xea\x1a\x33\xb7\x9c\xf3\x5b\x89\x88\x37\x01\x6e\xb2\x11"
+ "\xa1\x73\x4c\x7a\xf0\x76\xe1\x54\x51\xe3\x35\x19\xfc\x97\x8f\x66\xdf\x7d"
+ "\xf4\x55\x7c\x91\x02\x4a\x8d\xc1\x30\xa2\x8e\xf5\xf6\x3a\xd0\x7b\x39\xc8"
+ "\xd2\x3b\x85\xcf\x43\x4e\x06\x5e\x8a\x29\xa8\x00\x47\xfe\x17\xde\xe6\xf6"
+ "\x34\x7b\x49\x51\xf9\x7b\x57\x03\xdc\x78\xb1\xca\x9d\x74\xea\x6a\x9a\xe1"
+ "\x2a\xb3\x67\xc0\xde\x26\x59\xcc\x38\xd2\xf3\x3d\xdd\x86\xe0\x59\x7d\x33"
+ "\x36\x1e\xad\xa1\x19\xb5\x13\x21\x45\xfa\x45\x25\xc4\x88\xc7\xff\xfd\x6c"
+ "\xed\xa6\xe9\xa0\x2e\xbd\x97\xce\xd6\xb0\x16\x1f\x2c\xc8\x46\x15\xce\xb8"
+ "\xb1\x88\x83\x29\x9c\x63\x6e\x9e\x46\x72\x4a\x9a\x06\x00\xa8\xbb\x02\xf3"
+ "\xe4\x89\x63\x1d\x52\x20\x19\xa3\x5f\xe1\x2a\x33\xca\xf9\xdd\x87\x68\xdd"
+ "\xbc\x02\xa4\x84\xc3\x45\xc3\xef\xf2\x54\x29\x7b\x1d\xbb\x04\x98\x9c\x3f"
+ "\x9f\x3c\x7b\x3c\x98\x5c\x39\xb1\xd3\x13\x01\x80\x68\xd3\x80\x9b\xac\x8c"
+ "\x65\x7e\x39\xf4\xf6\x92\x61\x3e\x28\x38\x7e\x95\x57\x22\x90\x8d\x4b\x8b"
+ "\x56\x16\x3b\xe8\x31\x2f\xf4\x7c\x5b\x6f\x28\x04\x72\x93\x5a\xf7\x4e\x97"
+ "\xa5\xa8\x11\x0a\x4d\x74\x49\x6f\x4c\x8e\x88\x2d\xdb\x56\xd9\xb9\x62\xd2"
+ "\xfc\x43\xfa\x01\xa0\x47\x52\x68\x65\xc8\x4f\x7c\xff\x36\x05\x6c\xc4\xac"
+ "\x25\x80\x21\xe1\x58\x1d\x43\xba\xda\xae\xc6\xcc\x5a\x2e\xf9\x89\xde\x98"
+ "\x01\xfe\xd6\xd4\xbe\x2b\xfc\xfe\x07\xa6\x9c\x46\xbf\xfb\xe9\xdd\x03\x97"
+ "\x08\x00\x00\x00\x00\x00\x00\x00\xd3\x72\xbd\xd6\xd8\x9d\xc1\xec\xf6\x3c"
+ "\x23\xd5\x06\x11\x4d\x0f\xba\x2b\xd1\xc6\x9e\x8f\x7e\x3f\xcc\xdc\xda\x85"
+ "\xce\x97\x5e\xc1\x38\x1b\x1c\xec\x6d\xda\xa7\x6e\x18\x67\x19\xd8\x19\x16"
+ "\x43\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 1024);
+ syscall(__NR_ioctl, r[2], 0x4400ae8ful, 0x200004c0ul);
+ *(uint32_t*)0x200003c0 = 0;
+ *(uint32_t*)0x200003c4 = 0;
+ *(uint64_t*)0x200003c8 = 0x500;
+ *(uint32_t*)0x200003d0 = 0;
+ *(uint32_t*)0x200003d4 = 0;
+ *(uint32_t*)0x200003d8 = 0;
+ *(uint32_t*)0x200003dc = 0;
+ *(uint8_t*)0x200003e0 = 0;
+ *(uint8_t*)0x200003e1 = 0;
+ *(uint8_t*)0x200003e2 = 0;
+ *(uint8_t*)0x200003e3 = 0;
+ *(uint8_t*)0x200003e4 = 0;
+ *(uint8_t*)0x200003e5 = 0;
+ *(uint8_t*)0x200003e6 = 0;
+ *(uint8_t*)0x200003e7 = 0;
+ *(uint8_t*)0x200003e8 = 0;
+ *(uint8_t*)0x200003e9 = 0;
+ *(uint8_t*)0x200003ea = 0;
+ *(uint8_t*)0x200003eb = 0;
+ *(uint8_t*)0x200003ec = 0;
+ *(uint8_t*)0x200003ed = 0;
+ *(uint8_t*)0x200003ee = 0;
+ *(uint8_t*)0x200003ef = 0;
+ *(uint8_t*)0x200003f0 = 0;
+ *(uint8_t*)0x200003f1 = 0;
+ *(uint8_t*)0x200003f2 = 0;
+ *(uint8_t*)0x200003f3 = 0;
+ *(uint8_t*)0x200003f4 = 0;
+ *(uint8_t*)0x200003f5 = 0;
+ *(uint8_t*)0x200003f6 = 0;
+ *(uint8_t*)0x200003f7 = 0;
+ *(uint8_t*)0x200003f8 = 0;
+ *(uint8_t*)0x200003f9 = 0;
+ *(uint8_t*)0x200003fa = 0;
+ *(uint8_t*)0x200003fb = 0;
+ *(uint8_t*)0x200003fc = 0;
+ *(uint8_t*)0x200003fd = 0;
+ *(uint8_t*)0x200003fe = 0;
+ *(uint8_t*)0x200003ff = 0;
+ *(uint8_t*)0x20000400 = 0;
+ *(uint8_t*)0x20000401 = 0;
+ *(uint8_t*)0x20000402 = 0;
+ *(uint8_t*)0x20000403 = 0;
+ *(uint8_t*)0x20000404 = 0;
+ *(uint8_t*)0x20000405 = 0;
+ *(uint8_t*)0x20000406 = 0;
+ *(uint8_t*)0x20000407 = 0;
+ *(uint8_t*)0x20000408 = 0;
+ *(uint8_t*)0x20000409 = 0;
+ *(uint8_t*)0x2000040a = 0;
+ *(uint8_t*)0x2000040b = 0;
+ *(uint8_t*)0x2000040c = 0;
+ *(uint8_t*)0x2000040d = 0;
+ *(uint8_t*)0x2000040e = 0;
+ *(uint8_t*)0x2000040f = 0;
+ *(uint8_t*)0x20000410 = 0;
+ *(uint8_t*)0x20000411 = 0;
+ *(uint8_t*)0x20000412 = 0;
+ *(uint8_t*)0x20000413 = 0;
+ *(uint8_t*)0x20000414 = 0;
+ *(uint8_t*)0x20000415 = 0;
+ *(uint8_t*)0x20000416 = 0;
+ *(uint8_t*)0x20000417 = 0;
+ *(uint8_t*)0x20000418 = 0;
+ *(uint8_t*)0x20000419 = 0;
+ *(uint8_t*)0x2000041a = 0;
+ *(uint8_t*)0x2000041b = 0;
+ *(uint8_t*)0x2000041c = 0;
+ *(uint8_t*)0x2000041d = 0;
+ *(uint8_t*)0x2000041e = 0;
+ *(uint8_t*)0x2000041f = 0;
+ *(uint8_t*)0x20000420 = 0;
+ *(uint8_t*)0x20000421 = 0;
+ *(uint8_t*)0x20000422 = 0;
+ *(uint8_t*)0x20000423 = 0;
+ *(uint8_t*)0x20000424 = 0;
+ *(uint8_t*)0x20000425 = 0;
+ *(uint8_t*)0x20000426 = 0;
+ *(uint8_t*)0x20000427 = 0;
+ *(uint8_t*)0x20000428 = 0;
+ *(uint8_t*)0x20000429 = 0;
+ *(uint8_t*)0x2000042a = 0;
+ *(uint8_t*)0x2000042b = 0;
+ *(uint8_t*)0x2000042c = 0;
+ *(uint8_t*)0x2000042d = 0;
+ *(uint8_t*)0x2000042e = 0;
+ *(uint8_t*)0x2000042f = 0;
+ *(uint8_t*)0x20000430 = 0;
+ *(uint8_t*)0x20000431 = 0;
+ *(uint8_t*)0x20000432 = 0;
+ *(uint8_t*)0x20000433 = 0;
+ *(uint8_t*)0x20000434 = 0;
+ *(uint8_t*)0x20000435 = 0;
+ *(uint8_t*)0x20000436 = 0;
+ *(uint8_t*)0x20000437 = 0;
+ *(uint8_t*)0x20000438 = 0;
+ *(uint8_t*)0x20000439 = 0;
+ *(uint8_t*)0x2000043a = 0;
+ *(uint8_t*)0x2000043b = 0;
+ *(uint8_t*)0x2000043c = 0;
+ *(uint8_t*)0x2000043d = 0;
+ *(uint8_t*)0x2000043e = 0;
+ *(uint8_t*)0x2000043f = 0;
+ *(uint8_t*)0x20000440 = 0;
+ *(uint8_t*)0x20000441 = 0;
+ *(uint8_t*)0x20000442 = 0;
+ *(uint8_t*)0x20000443 = 0;
+ *(uint8_t*)0x20000444 = 0;
+ *(uint8_t*)0x20000445 = 0;
+ *(uint8_t*)0x20000446 = 0;
+ *(uint8_t*)0x20000447 = 0;
+ *(uint8_t*)0x20000448 = 0;
+ *(uint8_t*)0x20000449 = 0;
+ *(uint8_t*)0x2000044a = 0;
+ *(uint8_t*)0x2000044b = 0;
+ *(uint8_t*)0x2000044c = 0;
+ *(uint8_t*)0x2000044d = 0;
+ *(uint8_t*)0x2000044e = 0;
+ *(uint8_t*)0x2000044f = 0;
+ *(uint8_t*)0x20000450 = 0;
+ *(uint8_t*)0x20000451 = 0;
+ *(uint8_t*)0x20000452 = 0;
+ *(uint8_t*)0x20000453 = 0;
+ *(uint8_t*)0x20000454 = 0;
+ *(uint8_t*)0x20000455 = 0;
+ *(uint8_t*)0x20000456 = 0;
+ *(uint8_t*)0x20000457 = 0;
+ *(uint8_t*)0x20000458 = 0;
+ *(uint8_t*)0x20000459 = 0;
+ *(uint8_t*)0x2000045a = 0;
+ *(uint8_t*)0x2000045b = 0;
+ *(uint8_t*)0x2000045c = 0;
+ *(uint8_t*)0x2000045d = 0;
+ *(uint8_t*)0x2000045e = 0;
+ *(uint8_t*)0x2000045f = 0;
+ *(uint8_t*)0x20000460 = 0;
+ *(uint8_t*)0x20000461 = 0;
+ *(uint8_t*)0x20000462 = 0;
+ *(uint8_t*)0x20000463 = 0;
+ *(uint8_t*)0x20000464 = 0;
+ *(uint8_t*)0x20000465 = 0;
+ *(uint8_t*)0x20000466 = 0;
+ *(uint8_t*)0x20000467 = 0;
+ *(uint8_t*)0x20000468 = 0;
+ *(uint8_t*)0x20000469 = 0;
+ *(uint8_t*)0x2000046a = 0;
+ *(uint8_t*)0x2000046b = 0;
+ *(uint8_t*)0x2000046c = 0;
+ *(uint8_t*)0x2000046d = 0;
+ *(uint8_t*)0x2000046e = 0;
+ *(uint8_t*)0x2000046f = 0;
+ *(uint8_t*)0x20000470 = 0;
+ *(uint8_t*)0x20000471 = 0;
+ *(uint8_t*)0x20000472 = 0;
+ *(uint8_t*)0x20000473 = 0;
+ *(uint8_t*)0x20000474 = 0;
+ *(uint8_t*)0x20000475 = 0;
+ *(uint8_t*)0x20000476 = 0;
+ *(uint8_t*)0x20000477 = 0;
+ *(uint8_t*)0x20000478 = 0;
+ *(uint8_t*)0x20000479 = 0;
+ *(uint8_t*)0x2000047a = 0;
+ *(uint8_t*)0x2000047b = 0;
+ *(uint8_t*)0x2000047c = 0;
+ *(uint8_t*)0x2000047d = 0;
+ *(uint8_t*)0x2000047e = 0;
+ *(uint8_t*)0x2000047f = 0;
+ *(uint8_t*)0x20000480 = 0;
+ *(uint8_t*)0x20000481 = 0;
+ *(uint8_t*)0x20000482 = 0;
+ *(uint8_t*)0x20000483 = 0;
+ *(uint8_t*)0x20000484 = 0;
+ *(uint8_t*)0x20000485 = 0;
+ *(uint8_t*)0x20000486 = 0;
+ *(uint8_t*)0x20000487 = 0;
+ *(uint8_t*)0x20000488 = 0;
+ *(uint8_t*)0x20000489 = 0;
+ *(uint8_t*)0x2000048a = 0;
+ *(uint8_t*)0x2000048b = 0;
+ *(uint8_t*)0x2000048c = 0;
+ *(uint8_t*)0x2000048d = 0;
+ *(uint8_t*)0x2000048e = 0;
+ *(uint8_t*)0x2000048f = 0;
+ *(uint8_t*)0x20000490 = 0;
+ *(uint8_t*)0x20000491 = 0;
+ *(uint8_t*)0x20000492 = 0;
+ *(uint8_t*)0x20000493 = 0;
+ *(uint8_t*)0x20000494 = 0;
+ *(uint8_t*)0x20000495 = 0;
+ *(uint8_t*)0x20000496 = 0;
+ *(uint8_t*)0x20000497 = 0;
+ *(uint8_t*)0x20000498 = 0;
+ *(uint8_t*)0x20000499 = 0;
+ *(uint8_t*)0x2000049a = 0;
+ *(uint8_t*)0x2000049b = 0;
+ *(uint8_t*)0x2000049c = 0;
+ *(uint8_t*)0x2000049d = 0;
+ *(uint8_t*)0x2000049e = 0;
+ *(uint8_t*)0x2000049f = 0;
+ syscall(__NR_ioctl, r[1], 0x4020aea5ul, 0x200003c0ul);
+ syscall(__NR_ioctl, r[2], 0x8004ae98ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/10857c3f8515a6269522e043228547504abd6455.c b/syzkaller-repros/linux/10857c3f8515a6269522e043228547504abd6455.c
new file mode 100644
index 0000000..ecba1e9
--- /dev/null
+++ b/syzkaller-repros/linux/10857c3f8515a6269522e043228547504abd6455.c
@@ -0,0 +1,341 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0x300;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = -1;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0x20;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint32_t*)0x200000b8 = 0;
+ *(uint32_t*)0x200000bc = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000040ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_ioctl, r[1], 0x5606ul, 9ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/10885c48e038cebd26bcf4ae0c0daa0c6b0607a9.c b/syzkaller-repros/linux/10885c48e038cebd26bcf4ae0c0daa0c6b0607a9.c
new file mode 100644
index 0000000..6a96b5c
--- /dev/null
+++ b/syzkaller-repros/linux/10885c48e038cebd26bcf4ae0c0daa0c6b0607a9.c
@@ -0,0 +1,711 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, -1, 0x81009431ul, 0ul);
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0x20;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint32_t*)0x200000b8 = 0;
+ *(uint32_t*)0x200000bc = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0x200;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 7;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000040ul);
+ syscall(__NR_ioctl, -1, 0x4b67ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1252759d5b2a86c155d9c9d806902955d4edddca.c b/syzkaller-repros/linux/1252759d5b2a86c155d9c9d806902955d4edddca.c
new file mode 100644
index 0000000..c37c25c
--- /dev/null
+++ b/syzkaller-repros/linux/1252759d5b2a86c155d9c9d806902955d4edddca.c
@@ -0,0 +1,2024 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 3; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ break;
+ case 1:
+ res = syscall(__NR_socket, 0xaul, 1ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ NONFAILING(memcpy(
+ (void*)0x20000000,
+ "\x72\x61\x77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc1\x03"
+ "\x00\x00\x03\x00\x00\x00\x30\x05\x00\x00\x00\x00\x00\x00\x68\x02\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x68\x02\x00\x00\x60\x04\x00\x00"
+ "\x60\x04\x00\x00\x60\x04\x00\x00\x60\x04\x00\x00\x60\x04\x00\x00\x03"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x02"
+ "\x68\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50\x01\x68\x61\x73\x68\x6c\x69"
+ "\x6d\x69\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x02\x68\x73\x72\x30\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\x9f\x14\x52\x5e\xe3"
+ "\x22\xc8\x05\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x28\x00\x72\x70\x66\x69\x6c\x74\x65\x72\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x48\x00\x43\x54\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x01\x00"
+ "\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\xfe\x80"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\xff\x02\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
+ "\xff\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x0c"
+ "\x39\x66\x0c\xff\x00\x00\xff\x00\x00\x00\x00\x77\x67\x32\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x74\x65\x61\x6d\x30\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\xd0\x00\xf8\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x69\x70"
+ "\x76\x36\x68\x65\x61\x64\x65\x72\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x28\x01\x53\x45\x43\x4d\x41\x52\x4b\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x73\x79\x73\x74\x65\x6d\x5f\x75\x3a"
+ "\x6f\x62\x6a\x65\x63\x74\x5f\x72\x3a\x75\x70\x64\x61\x74\x65\x5f\x6d"
+ "\x6f\x64\x75\x6c\x65\x73\x5f\x65\x78\x65\x63\x5f\x74\x3a\x73\x30\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\x00\xd0\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\xfe\xff\xff\xff",
+ 1420));
+ syscall(__NR_setsockopt, r[0], 0x29ul, 0x40ul, 0x20000000ul, 1ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/13c53700ac03326096676d67fb7627427bef4972.c b/syzkaller-repros/linux/13c53700ac03326096676d67fb7627427bef4972.c
new file mode 100644
index 0000000..ae6ace0
--- /dev/null
+++ b/syzkaller-repros/linux/13c53700ac03326096676d67fb7627427bef4972.c
@@ -0,0 +1,460 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+#ifndef __NR_io_uring_setup
+#define __NR_io_uring_setup 425
+#endif
+
+void execute_one(void)
+{
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0ul, 0ul);
+ syscall(__NR_perf_event_open, 0ul, 0, -1ul, -1, 0ul);
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 7;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint64_t*)0x20000088 = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint64_t*)0x200000b0 = 0;
+ inject_fault(3);
+ syscall(__NR_io_uring_setup, 0xe44, 0x20000040ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/13d6115680ddcb83172032bfa474b252fd00924c.c b/syzkaller-repros/linux/13d6115680ddcb83172032bfa474b252fd00924c.c
new file mode 100644
index 0000000..9f95c67
--- /dev/null
+++ b/syzkaller-repros/linux/13d6115680ddcb83172032bfa474b252fd00924c.c
@@ -0,0 +1,433 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+
+ *(uint8_t*)0x20000080 = 0x12;
+ *(uint8_t*)0x20000081 = 1;
+ *(uint16_t*)0x20000082 = 0;
+ *(uint8_t*)0x20000084 = 0x11;
+ *(uint8_t*)0x20000085 = 0xe2;
+ *(uint8_t*)0x20000086 = 0x57;
+ *(uint8_t*)0x20000087 = 8;
+ *(uint16_t*)0x20000088 = 0x846;
+ *(uint16_t*)0x2000008a = 0x9041;
+ *(uint16_t*)0x2000008c = 0xd5fc;
+ *(uint8_t*)0x2000008e = 0;
+ *(uint8_t*)0x2000008f = 0;
+ *(uint8_t*)0x20000090 = 0;
+ *(uint8_t*)0x20000091 = 1;
+ *(uint8_t*)0x20000092 = 9;
+ *(uint8_t*)0x20000093 = 2;
+ *(uint16_t*)0x20000094 = 0x7c;
+ *(uint8_t*)0x20000096 = 1;
+ *(uint8_t*)0x20000097 = 0;
+ *(uint8_t*)0x20000098 = 0;
+ *(uint8_t*)0x20000099 = 0;
+ *(uint8_t*)0x2000009a = 0;
+ *(uint8_t*)0x2000009b = 9;
+ *(uint8_t*)0x2000009c = 4;
+ *(uint8_t*)0x2000009d = 8;
+ *(uint8_t*)0x2000009e = 0;
+ *(uint8_t*)0x2000009f = 0xa;
+ *(uint8_t*)0x200000a0 = 9;
+ *(uint8_t*)0x200000a1 = 0x88;
+ *(uint8_t*)0x200000a2 = 0xae;
+ *(uint8_t*)0x200000a3 = 0xfd;
+ *(uint8_t*)0x200000a4 = 7;
+ *(uint8_t*)0x200000a5 = 5;
+ *(uint8_t*)0x200000a6 = 3;
+ *(uint8_t*)0x200000a7 = 0;
+ *(uint16_t*)0x200000a8 = 0x1ff;
+ *(uint8_t*)0x200000aa = 8;
+ *(uint8_t*)0x200000ab = -1;
+ *(uint8_t*)0x200000ac = 6;
+ *(uint8_t*)0x200000ad = 7;
+ *(uint8_t*)0x200000ae = 5;
+ *(uint8_t*)0x200000af = 0x64;
+ *(uint8_t*)0x200000b0 = 0x10;
+ *(uint16_t*)0x200000b1 = 5;
+ *(uint8_t*)0x200000b3 = 8;
+ *(uint8_t*)0x200000b4 = 1;
+ *(uint8_t*)0x200000b5 = 1;
+ *(uint8_t*)0x200000b6 = 7;
+ *(uint8_t*)0x200000b7 = 5;
+ *(uint8_t*)0x200000b8 = 2;
+ *(uint8_t*)0x200000b9 = 0;
+ *(uint16_t*)0x200000ba = 9;
+ *(uint8_t*)0x200000bc = 0x94;
+ *(uint8_t*)0x200000bd = 9;
+ *(uint8_t*)0x200000be = 8;
+ *(uint8_t*)0x200000bf = 2;
+ *(uint8_t*)0x200000c0 = 0x24;
+ *(uint8_t*)0x200000c1 = 7;
+ *(uint8_t*)0x200000c2 = 5;
+ *(uint8_t*)0x200000c3 = 0;
+ *(uint8_t*)0x200000c4 = 0;
+ *(uint16_t*)0x200000c5 = 6;
+ *(uint8_t*)0x200000c7 = 0;
+ *(uint8_t*)0x200000c8 = 0x23;
+ *(uint8_t*)0x200000c9 = 0x1f;
+ *(uint8_t*)0x200000ca = 2;
+ *(uint8_t*)0x200000cb = 0x21;
+ *(uint8_t*)0x200000cc = 7;
+ *(uint8_t*)0x200000cd = 5;
+ *(uint8_t*)0x200000ce = 4;
+ *(uint8_t*)0x200000cf = 0;
+ *(uint16_t*)0x200000d0 = 0x40;
+ *(uint8_t*)0x200000d2 = 0xc3;
+ *(uint8_t*)0x200000d3 = -1;
+ *(uint8_t*)0x200000d4 = 0;
+ *(uint8_t*)0x200000d5 = 2;
+ *(uint8_t*)0x200000d6 = 0x23;
+ *(uint8_t*)0x200000d7 = 2;
+ *(uint8_t*)0x200000d8 = 7;
+ *(uint8_t*)0x200000d9 = 7;
+ *(uint8_t*)0x200000da = 5;
+ *(uint8_t*)0x200000db = 1;
+ *(uint8_t*)0x200000dc = 0;
+ *(uint16_t*)0x200000dd = 0x1000;
+ *(uint8_t*)0x200000df = 0;
+ *(uint8_t*)0x200000e0 = -1;
+ *(uint8_t*)0x200000e1 = 7;
+ *(uint8_t*)0x200000e2 = 7;
+ *(uint8_t*)0x200000e3 = 5;
+ *(uint8_t*)0x200000e4 = 0x7f;
+ *(uint8_t*)0x200000e5 = 0;
+ *(uint16_t*)0x200000e6 = 5;
+ *(uint8_t*)0x200000e8 = 0;
+ *(uint8_t*)0x200000e9 = 6;
+ *(uint8_t*)0x200000ea = 3;
+ *(uint8_t*)0x200000eb = 2;
+ *(uint8_t*)0x200000ec = 0x33;
+ *(uint8_t*)0x200000ed = 2;
+ *(uint8_t*)0x200000ee = 4;
+ *(uint8_t*)0x200000ef = 7;
+ *(uint8_t*)0x200000f0 = 5;
+ *(uint8_t*)0x200000f1 = 0;
+ *(uint8_t*)0x200000f2 = 3;
+ *(uint16_t*)0x200000f3 = 0x1000;
+ *(uint8_t*)0x200000f5 = 0;
+ *(uint8_t*)0x200000f6 = 0xa3;
+ *(uint8_t*)0x200000f7 = 0;
+ *(uint8_t*)0x200000f8 = 7;
+ *(uint8_t*)0x200000f9 = 5;
+ *(uint8_t*)0x200000fa = 0x93;
+ *(uint8_t*)0x200000fb = 0xc;
+ *(uint16_t*)0x200000fc = 5;
+ *(uint8_t*)0x200000fe = 0xf8;
+ *(uint8_t*)0x200000ff = 4;
+ *(uint8_t*)0x20000100 = 5;
+ *(uint8_t*)0x20000101 = 2;
+ *(uint8_t*)0x20000102 = 0xc;
+ *(uint8_t*)0x20000103 = 7;
+ *(uint8_t*)0x20000104 = 5;
+ *(uint8_t*)0x20000105 = 5;
+ *(uint8_t*)0x20000106 = 0;
+ *(uint16_t*)0x20000107 = -1;
+ *(uint8_t*)0x20000109 = 0x40;
+ *(uint8_t*)0x2000010a = 0xa7;
+ *(uint8_t*)0x2000010b = 2;
+ *(uint8_t*)0x2000010c = 2;
+ *(uint8_t*)0x2000010d = 0;
+ syz_usb_connect(0x147d406270ea0977, 0x8e, 0x20000080, 0);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1685ca842eda44456e1b2dc3d7136b603f6faa95.c b/syzkaller-repros/linux/1685ca842eda44456e1b2dc3d7136b603f6faa95.c
new file mode 100644
index 0000000..3a71102
--- /dev/null
+++ b/syzkaller-repros/linux/1685ca842eda44456e1b2dc3d7136b603f6faa95.c
@@ -0,0 +1,460 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_openat, 0xffffff9c, 0ul, 0x7a05ul, 0x1700ul);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x6609ul, 0ul);
+ syscall(__NR_setsockopt, r[0], 6ul, 0x15ul, 0ul, 0ul);
+ res = syscall(__NR_socket, 2ul, 5ul, 0x84ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000440 = 0x20000000;
+ *(uint16_t*)0x20000000 = 2;
+ *(uint16_t*)0x20000002 = htobe16(0);
+ *(uint8_t*)0x20000004 = 0xac;
+ *(uint8_t*)0x20000005 = 0x14;
+ *(uint8_t*)0x20000006 = 0x14;
+ *(uint8_t*)0x20000007 = 0xaa;
+ *(uint32_t*)0x20000448 = 0x10;
+ *(uint64_t*)0x20000450 = 0x20000100;
+ *(uint64_t*)0x20000100 = 0x20000040;
+ memcpy((void*)0x20000040, "\xc8", 1);
+ *(uint64_t*)0x20000108 = 1;
+ *(uint64_t*)0x20000458 = 1;
+ *(uint64_t*)0x20000460 = 0x200003c0;
+ *(uint64_t*)0x200003c0 = 0x18;
+ *(uint32_t*)0x200003c8 = 0x84;
+ *(uint32_t*)0x200003cc = 0;
+ *(uint16_t*)0x200003d0 = 0x8000;
+ *(uint16_t*)0x200003d2 = 0;
+ *(uint16_t*)0x200003d4 = 0;
+ *(uint16_t*)0x200003d6 = 8;
+ *(uint64_t*)0x20000468 = 0x18;
+ *(uint32_t*)0x20000470 = 0;
+ inject_fault(60);
+ syscall(__NR_sendmsg, r[1], 0x20000440ul, 0x50ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1765579448a7235f40e5107c35e958fe83e266aa.c b/syzkaller-repros/linux/1765579448a7235f40e5107c35e958fe83e266aa.c
new file mode 100644
index 0000000..7ca4a21
--- /dev/null
+++ b/syzkaller-repros/linux/1765579448a7235f40e5107c35e958fe83e266aa.c
@@ -0,0 +1,176 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1)
+
+#define BITMASK_LEN_OFF(type, bf_off, bf_len) \
+ (type)(BITMASK_LEN(type, (bf_len)) << (bf_off))
+
+#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \
+ if ((bf_off) == 0 && (bf_len) == 0) { \
+ *(type*)(addr) = (type)(val); \
+ } else { \
+ type new_val = *(type*)(addr); \
+ new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \
+ new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \
+ *(type*)(addr) = new_val; \
+ }
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ *(uint32_t*)0x20000140 = 2;
+ *(uint32_t*)0x20000144 = 0x70;
+ *(uint8_t*)0x20000148 = 0xe3;
+ *(uint8_t*)0x20000149 = 0;
+ *(uint8_t*)0x2000014a = 0;
+ *(uint8_t*)0x2000014b = 0;
+ *(uint32_t*)0x2000014c = 0;
+ *(uint64_t*)0x20000150 = 0;
+ *(uint64_t*)0x20000158 = 0;
+ *(uint64_t*)0x20000160 = 0;
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 0, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 1, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 2, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 3, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 4, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 5, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 6, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 7, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 8, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 9, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 10, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 11, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 12, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 13, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 14, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 15, 2);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 17, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 18, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 19, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 20, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 21, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 22, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 23, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 24, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 25, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 26, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 27, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 28, 1);
+ STORE_BY_BITMASK(uint64_t, 0x20000168, 0, 29, 35);
+ *(uint32_t*)0x20000170 = 0;
+ *(uint32_t*)0x20000174 = 0;
+ *(uint64_t*)0x20000178 = 0x20000080;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint64_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0;
+ *(uint32_t*)0x20000198 = 0;
+ *(uint32_t*)0x2000019c = 0;
+ *(uint64_t*)0x200001a0 = 0;
+ *(uint32_t*)0x200001a8 = 0;
+ *(uint16_t*)0x200001ac = 0;
+ *(uint16_t*)0x200001ae = 0;
+ syscall(__NR_perf_event_open, 0x20000140, 0, -1, -1, 0);
+ break;
+ case 1:
+ syscall(__NR_pipe, 0x20000200);
+ break;
+ case 2:
+ memcpy((void*)0x20000700, "./bus", 6);
+ res = syscall(__NR_creat, 0x20000700, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 3:
+ memcpy((void*)0x20000280, "./bus", 6);
+ memcpy((void*)0x200002c0, "./file1", 8);
+ syscall(__NR_rename, 0x20000280, 0x200002c0);
+ break;
+ case 4:
+ syscall(__NR_ftruncate, r[0], 0x8200);
+ break;
+ }
+}
+
+void loop()
+{
+ execute(5);
+ collide = 1;
+ execute(5);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/18620d1d7244eb6eb5faef1960308b81f7946ef6.c b/syzkaller-repros/linux/18620d1d7244eb6eb5faef1960308b81f7946ef6.c
new file mode 100644
index 0000000..6412f95
--- /dev/null
+++ b/syzkaller-repros/linux/18620d1d7244eb6eb5faef1960308b81f7946ef6.c
@@ -0,0 +1,1405 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_ioctl, r[0], 0x4b61ul, 0x20000040ul);
+ break;
+ case 2:
+ NONFAILING(memcpy((void*)0x20000000, "/dev/fb0\000", 9));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ NONFAILING(*(uint32_t*)0x20000040 = 0);
+ NONFAILING(*(uint32_t*)0x20000044 = 0);
+ NONFAILING(*(uint32_t*)0x20000048 = 0);
+ NONFAILING(*(uint32_t*)0x2000004c = 0);
+ NONFAILING(*(uint32_t*)0x20000050 = 0);
+ NONFAILING(*(uint32_t*)0x20000054 = 0);
+ NONFAILING(*(uint32_t*)0x20000058 = 0x20);
+ NONFAILING(*(uint32_t*)0x2000005c = 0);
+ NONFAILING(*(uint32_t*)0x20000060 = 0);
+ NONFAILING(*(uint32_t*)0x20000064 = 0);
+ NONFAILING(*(uint32_t*)0x20000068 = 0);
+ NONFAILING(*(uint32_t*)0x2000006c = 0);
+ NONFAILING(*(uint32_t*)0x20000070 = 0);
+ NONFAILING(*(uint32_t*)0x20000074 = 0);
+ NONFAILING(*(uint32_t*)0x20000078 = 0);
+ NONFAILING(*(uint32_t*)0x2000007c = 0);
+ NONFAILING(*(uint32_t*)0x20000080 = 0);
+ NONFAILING(*(uint32_t*)0x20000084 = 0);
+ NONFAILING(*(uint32_t*)0x20000088 = 0);
+ NONFAILING(*(uint32_t*)0x2000008c = 0);
+ NONFAILING(*(uint32_t*)0x20000090 = 0);
+ NONFAILING(*(uint32_t*)0x20000094 = 0);
+ NONFAILING(*(uint32_t*)0x20000098 = 0);
+ NONFAILING(*(uint32_t*)0x2000009c = 0);
+ NONFAILING(*(uint32_t*)0x200000a0 = 0);
+ NONFAILING(*(uint32_t*)0x200000a4 = 6);
+ NONFAILING(*(uint32_t*)0x200000a8 = 0);
+ NONFAILING(*(uint32_t*)0x200000ac = 0);
+ NONFAILING(*(uint32_t*)0x200000b0 = 0);
+ NONFAILING(*(uint32_t*)0x200000b4 = 0);
+ NONFAILING(*(uint32_t*)0x200000b8 = 0);
+ NONFAILING(*(uint32_t*)0x200000bc = 0);
+ NONFAILING(*(uint32_t*)0x200000c0 = 0);
+ NONFAILING(*(uint32_t*)0x200000c4 = 0);
+ NONFAILING(*(uint32_t*)0x200000c8 = 0);
+ NONFAILING(*(uint32_t*)0x200000cc = 0);
+ NONFAILING(*(uint32_t*)0x200000d0 = 0);
+ NONFAILING(*(uint32_t*)0x200000d4 = 0);
+ NONFAILING(*(uint32_t*)0x200000d8 = 0);
+ NONFAILING(*(uint32_t*)0x200000dc = 0);
+ syscall(__NR_ioctl, r[1], 0x4601ul, 0x20000040ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/191a661bce16b8880ce500d058c7c7e69fbc8056.c b/syzkaller-repros/linux/191a661bce16b8880ce500d058c7c7e69fbc8056.c
new file mode 100644
index 0000000..53e47e9
--- /dev/null
+++ b/syzkaller-repros/linux/191a661bce16b8880ce500d058c7c7e69fbc8056.c
@@ -0,0 +1,378 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 1;
+ *(uint32_t*)0x2000000c = 3;
+ *(uint32_t*)0x20000010 = 0x100;
+ *(uint64_t*)0x20000018 = 0x200003c0;
+ memcpy(
+ (void*)0x200003c0,
+ "\xcb\xb6\x2c\x7c\x7e\x12\x72\x7d\x60\xc5\xdb\x26\x5c\x1d\x8b\x3f\x75\x25"
+ "\x50\xd4\xea\xc7\xaf\xf1\x02\x13\x26\xe1\x5d\xfd\xad\x91\x1d\x57\xa8\x53"
+ "\x41\x4b\x19\x47\x02\xa4\x1a\x75\x60\x56\x8b\xe1\x11\x1d\xac\x9f\xf2\x58"
+ "\x6d\x67\xdc\x8e\xf3\xe9\xd3\x66\x94\xc5\xea\x96\xd8\x98\x5a\x99\x53\xe8"
+ "\x77\x5c\xbf\x7a\xe1\x51\xea\x1f\xd6\x1f\xbc\x2d\x44\xe7\x60\x31\x83\x3d"
+ "\xff\xb4\x47\xc4\x25\xc9\x74\x9c\x7d\xe7\xfb\xe2\xe5\x65\xb4\xa2\x5f\x7b"
+ "\x2a\xc0\x13\x92\xce\x04\xec\x8d\x6d\x21\x0e\x0a\x23\xae\x3a\x5f\xd8\x1c"
+ "\x3c\x89\xc9\x28\x74\x70\x9f\xcd\xd4\xd4\xc3\xff\xe7\xfa\x05\x2a\xc6\x8f"
+ "\xb6\xdf\x7e\x48\x2e\x24\xbe\x6a\xc8\x19\x10\x39\xb4\x34\xaa\x0e\x9f\x97"
+ "\x39\xae\xdf\x30\xc0\xfa\x9c\x42\xcd\xa4\x11\x02\x5c\xa2\x0c\x42\xbf\x88"
+ "\x68\x56\x03\x99\x87\x3f\x4d\x1b\x28\xed\x71\x3e\x41\x1b\x34\xec\x02\x63"
+ "\x21\xc8\xcd\x9a\xd1\x7c\xbc\x95\x70\x4c\x14\x2d\x7c\x71\x06\x3b\x4a\x0b"
+ "\x52\xe2\x20\x73\xf8\x59\xd6\x32\x89\x92\x12\x6e\x5f\x50\x57\xad\x1d\x02"
+ "\x29\xba\xde\xc1\xe0\x88\x0f\x47\x6f\x18\xce\x68\x55\x60\x78\xa0\x06\x7d"
+ "\x8e\x90\x05\x7f\x56\x0b\x51\x51\xc4\x50\xe6\x55\x89\x81\x2f\x77\x9b\x50"
+ "\xe4\xde\xd6\x60\xee\x4a\xa6\x1e\x7f\x84\xa9\xb4\xb7\x91\x83\x71\x14\x09"
+ "\x55\x39\xfb\x55\x73\xe4\x7c\xce\x26\xdc\x38\x31\x19\x13\x99\x51\x81\xe7"
+ "\x28\xfd\x4d\x6d\x33\x4e\x62\xfd\x0a\x82\x2f\x93\x71\xbc\xdc\x43\xc8\xa6"
+ "\x96\x88\xa1\x1f\xc9\xf4\x3a\xfe\x64\x2c\x30\xdd\xf3\x94\x65\xb1\x3c\xf1"
+ "\xdd\xad\xd7\x89\x70\x77\x18\x27\xf4\x45\xf0\xd4\x56\x1e\x8e\x2b\xb6\xcf"
+ "\x22\x44\x63\x4b\xcd\x72\xd1\x24\xf3\xca\xa1\x52\xc6\xfd\x6d\x47\xbb\x00"
+ "\x4b\x97\x97\x5d\x4a\x46\xb2\xee\x12\x9b\x88\x9d\xc5\x9c\x1c\x71\x62\xff"
+ "\xf2\x2c\x42\x95\x54\x52\x95\xea\x72\xfe\x14\xc6\xb2\xba\xb3\x5a\xb5\x45"
+ "\x51\x73\x98\xb0\x03\xb6\xd3\xb8\x9c\x5c\x64\xb4\x49\xf7\xd5\x60\xdd\xe2"
+ "\x0f\xc1\x3b\x3e\xc8\x8d\xc0\x52\x42\xa1\x60\x07\x6c\xcb\xff\x3e\x32\xb8"
+ "\x78\x0b\xd1\x91\xa0\xb1\x2a\x6f\x99\x00\xa9\x3f\xa1\x2d\x9f\xb5\xed\x34"
+ "\x88\xd5\xcd\x0a\xa3\x29\x58\x3f\x2c\x47\xc4\xfd\x47\x26\x46\x9c\x98\xe0"
+ "\xb6\x6d\x74\xc3\x1d\x0a\x1f\x7f\xc1\x0c\xc1\x94\x4d\x25\x26\x7e\xff\x7a"
+ "\x74\x0c\xc4\x30\x06\x9b\x58\x47\x9c\xa6\x96\x00\x63\x6a\x0f\x22\xa4\x70"
+ "\xa6\x9b\x46\xc1\xcc\x1b\x95\xcf\x32\xdd\x7b\x73\xad\x67\x41\x61\xca\x39"
+ "\x25\x83\xaa\x83\x4a\xaa\xde\x88\xa4\x39\x33\x89\xb7\x6d\x58\x8a\x60\x81"
+ "\x91\xdb\x7c\xa7\x5d\xd0\x09\x38\x2a\x45\x83\xe8\x78\x1e\xb0\x9f\x48\xa4"
+ "\x4d\x06\xb4\x17\x56\xeb\x3f\x1b\x7e\xea\x18\xad\xf2\x97\x83\x22\xd0\xb3"
+ "\x84\xdf\x03\x07\x98\x91\xe1\x0f\x09\x2c\x57\x33\x20\xfb\x94\x1f\x10\xe3"
+ "\xc3\xaf\x6f\x3e\x72\xb2\xaf\xcd\x95\xa3\x66\x6a\x6a\x40\xa8\x40\xe6\x3d"
+ "\x1c\xb9\xe2\x49\x25\xc0\x49\x7a\x04\xef\x7b\x9b\x1e\xe3\x9d\xe0\x45\x6f"
+ "\xec\xd6\x76\xac\xee\x23\x3f\x5b\x64\x5e\x8d\x05\xf3\xf5\x05\xa1\x2a\x0f"
+ "\x5b\x35\x65\x86\xf2\x2c\x2c\x2c\xeb\xef\x83\xc5\xe6\x8c\x22\x72\x34\x95"
+ "\xab\xa0\x64\x27\x92\x55\xde\x48\x9e\x33\xe9\x20\x9a\x63\x68\x90\xbc\xfb"
+ "\x2a\x52\x7e\x8d\xa8\x36\x21\xae\xf3\x74\xf5\xa1\x1d\x8a\xc7\x7f\x5d\xcd"
+ "\x42\x1f\x45\xe5\x2d\xdf\x9b\xc3\x5f\x64\xcf\x72\x1c\xe6\xc9\x6b\x56\x13"
+ "\x26\x8c\x02\x5c\xa9\x91\x0a\x8a\x23\x5e\x6a\xf3\xd6\x7a\xdd\xc6\x6e\x75"
+ "\xc1\x56\x4a\x7f\x86\x84\xfc\xd2\x3e\xc9\x8d\x61\xa4\xfa\x42\x2c\x55\xe6"
+ "\x78\x9c\xbc\x42\xb1\xd5\x32\x63\x3e\x65\x8a\x5c\x2f\xfe\x57\x67\x03\x97"
+ "\x62\xf1\x8c\xce\x89\xb8\x00\x0e\x37\xca\xbc\x35\x40\x9d\x3c\x7a\x02\x13"
+ "\xde\x87\xce\x95\xcf\xbf\xb0\xc7\x1b\xe4\xc4\xef\x44\x86\x6b\xd8\xe0\x50"
+ "\xe3\x36\xb3\x1a\x6e\x8f\x15\xbd\x21\x60\xe5\x48\x48\xad\xa2\x56\xdf\x90"
+ "\x27\x58\xeb\xbc\x1e\x83\x7f\xab\x4c\xb8\xbb\x84\x67\xa7\x3d\xf7\x17\xd9"
+ "\x2e\x22\x04\x48\x2f\xe9\x5c\x21\x12\x11\x86\xa5\x7c\x3b\x12\xf7\x5c\x83"
+ "\x6a\xb7\x02\x43\x34\x18\xf3\x29\x44\x32\x3e\xaa\xad\xbc\xa3\x66\x96\x1c"
+ "\x25\x62\x0c\x43\x95\x1a\x7a\x3f\xd3\xe3\xcc\x85\xd6\xa3\x99\x6b\x50\xd1"
+ "\x2e\xa7\x6d\xf6\x58\xa6\x40\x5f\xdf\x1c\x9f\x2c\x05\x24\x8d\x95\x15\xce"
+ "\x96\x65\x0e\xbf\x62\x96\x64\xe6\xc1\x92\xdd\x28\xe1\x61\x72\xbe\x15\x93"
+ "\xe9\x4d\xbc\xa0\xe5\x54\xfc\xe9\x73\x6c\x73\x54\x03\x0c\x64\xfd\xaf\x35"
+ "\x03\x8e\x1f\x1e\x1d\x20\xe0\x6f\x34\x8e\xf5\xae\x75\x41\x39\xb4\xe8\x12"
+ "\xc6\x0f\xbc\x55\xba\xce\x83\xf2\x7b\xb8\x35\xc1\x64\xc2\x9f\x5f\x7c\x1d"
+ "\xbe\xeb\xfd\x98\x8a\x16\x23\x5c\x4b\xbe\xe4\xd9\xa3\xbc\x66\x6f",
+ 1024);
+ syscall(__NR_ioctl, r[0], 0x4b72ul, 0x20000000ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x200001c0 = 0;
+ *(uint16_t*)0x200001c2 = 0x8000;
+ *(uint16_t*)0x200001c4 = 0x7fff;
+ *(uint16_t*)0x200001c6 = 0xc;
+ *(uint16_t*)0x200001c8 = 0;
+ *(uint16_t*)0x200001ca = 0;
+ syscall(__NR_ioctl, r[1], 0x560aul, 0x200001c0ul);
+ memcpy((void*)0x20000000, "/dev/vcsa\000\000", 11);
+ res = syz_open_dev(0x20000000, 0, 0x2001);
+ if (res != -1)
+ r[2] = res;
+ memcpy((void*)0x20000040, "\xf3\x72\x21\x50\xb4", 5);
+ syscall(__NR_write, r[2], 0x20000040ul, 0x20000045ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1a278e3f57cffaa7e62c84a6b0753070a836fe0a.c b/syzkaller-repros/linux/1a278e3f57cffaa7e62c84a6b0753070a836fe0a.c
new file mode 100644
index 0000000..21f3a4c
--- /dev/null
+++ b/syzkaller-repros/linux/1a278e3f57cffaa7e62c84a6b0753070a836fe0a.c
@@ -0,0 +1,267 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 137
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ netlink_send(&nlmsg, sock);
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ syscall(__NR_iopl, 3);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1a30aa6e8b48f0a37a2f70f1872e4c81f8b6c4be.c b/syzkaller-repros/linux/1a30aa6e8b48f0a37a2f70f1872e4c81f8b6c4be.c
new file mode 100644
index 0000000..d9aa7e8
--- /dev/null
+++ b/syzkaller-repros/linux/1a30aa6e8b48f0a37a2f70f1872e4c81f8b6c4be.c
@@ -0,0 +1,655 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 8; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ res = syscall(__NR_socket, 0x40000000015ul, 5ul, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ syscall(__NR_bind, r[1], 0ul, 0ul);
+ break;
+ case 3:
+ syscall(__NR_setsockopt, -1, 0x29ul, 0x23ul, 0ul, 0ul);
+ break;
+ case 4:
+ res = syscall(__NR_socket, 0xaul, 3ul, 7);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 5:
+ *(uint16_t*)0x200000c0 = 0xa;
+ *(uint16_t*)0x200000c2 = htobe16(0);
+ *(uint32_t*)0x200000c4 = htobe32(0);
+ *(uint64_t*)0x200000c8 = htobe64(0);
+ *(uint64_t*)0x200000d0 = htobe64(1);
+ *(uint32_t*)0x200000d8 = 0;
+ syscall(__NR_connect, r[2], 0x200000c0ul, 0x1cul);
+ break;
+ case 6:
+ syscall(__NR_sendmmsg, r[2], 0x20000480ul, 0x2e9ul, 0ul);
+ break;
+ case 7:
+ *(uint64_t*)0x20000180 = 0;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000980;
+ *(uint32_t*)0x20000980 = 0xf8;
+ *(uint16_t*)0x20000984 = 0x10;
+ *(uint16_t*)0x20000986 = 0x42b;
+ *(uint32_t*)0x20000988 = 0;
+ *(uint32_t*)0x2000098c = 0;
+ *(uint8_t*)0x20000990 = 0;
+ *(uint8_t*)0x20000991 = 0;
+ *(uint16_t*)0x20000992 = 0;
+ *(uint32_t*)0x20000994 = 0;
+ *(uint32_t*)0x20000998 = 0;
+ *(uint32_t*)0x2000099c = 0;
+ *(uint16_t*)0x200009a0 = 0xd8;
+ *(uint16_t*)0x200009a2 = 0x12;
+ *(uint16_t*)0x200009a4 = 8;
+ *(uint16_t*)0x200009a6 = 1;
+ memcpy((void*)0x200009a8, "gtp\000", 4);
+ *(uint16_t*)0x200009ac = 0xcc;
+ *(uint16_t*)0x200009ae = 2;
+ *(uint16_t*)0x200009b0 = 8;
+ *(uint16_t*)0x200009b2 = 1;
+ *(uint32_t*)0x200009b4 = -1;
+ *(uint16_t*)0x200009b8 = 8;
+ *(uint16_t*)0x200009ba = 2;
+ *(uint32_t*)0x200009bc = r[1];
+ *(uint16_t*)0x200009c0 = 8;
+ *(uint16_t*)0x200009c2 = 2;
+ *(uint32_t*)0x200009c4 = -1;
+ *(uint16_t*)0x200009c8 = 8;
+ *(uint16_t*)0x200009ca = 3;
+ *(uint32_t*)0x200009cc = 0;
+ *(uint16_t*)0x200009d0 = 8;
+ *(uint16_t*)0x200009d2 = 2;
+ *(uint32_t*)0x200009d4 = -1;
+ *(uint16_t*)0x200009d8 = 8;
+ *(uint16_t*)0x200009da = 3;
+ *(uint32_t*)0x200009dc = 7;
+ *(uint16_t*)0x200009e0 = 8;
+ *(uint16_t*)0x200009e2 = 3;
+ *(uint32_t*)0x200009e4 = 0x8001;
+ *(uint16_t*)0x200009e8 = 8;
+ *(uint16_t*)0x200009ea = 3;
+ *(uint32_t*)0x200009ec = 3;
+ *(uint16_t*)0x200009f0 = 8;
+ *(uint16_t*)0x200009f2 = 1;
+ *(uint32_t*)0x200009f4 = -1;
+ *(uint16_t*)0x200009f8 = 8;
+ *(uint16_t*)0x200009fa = 2;
+ *(uint32_t*)0x200009fc = -1;
+ *(uint16_t*)0x20000a00 = 8;
+ *(uint16_t*)0x20000a02 = 4;
+ *(uint32_t*)0x20000a04 = 0;
+ *(uint16_t*)0x20000a08 = 8;
+ *(uint16_t*)0x20000a0a = 2;
+ *(uint32_t*)0x20000a0c = -1;
+ *(uint16_t*)0x20000a10 = 8;
+ *(uint16_t*)0x20000a12 = 1;
+ *(uint32_t*)0x20000a14 = -1;
+ *(uint16_t*)0x20000a18 = 8;
+ *(uint16_t*)0x20000a1a = 2;
+ *(uint32_t*)0x20000a1c = -1;
+ *(uint16_t*)0x20000a20 = 8;
+ *(uint16_t*)0x20000a22 = 1;
+ *(uint32_t*)0x20000a24 = -1;
+ *(uint16_t*)0x20000a28 = 8;
+ *(uint16_t*)0x20000a2a = 1;
+ *(uint32_t*)0x20000a2c = -1;
+ *(uint16_t*)0x20000a30 = 8;
+ *(uint16_t*)0x20000a32 = 1;
+ *(uint32_t*)0x20000a34 = -1;
+ *(uint16_t*)0x20000a38 = 8;
+ *(uint16_t*)0x20000a3a = 1;
+ *(uint32_t*)0x20000a3c = -1;
+ *(uint16_t*)0x20000a40 = 8;
+ *(uint16_t*)0x20000a42 = 2;
+ *(uint32_t*)0x20000a44 = -1;
+ *(uint16_t*)0x20000a48 = 8;
+ *(uint16_t*)0x20000a4a = 4;
+ *(uint32_t*)0x20000a4c = 1;
+ *(uint16_t*)0x20000a50 = 8;
+ *(uint16_t*)0x20000a52 = 3;
+ *(uint32_t*)0x20000a54 = 0x20;
+ *(uint16_t*)0x20000a58 = 8;
+ *(uint16_t*)0x20000a5a = 4;
+ *(uint32_t*)0x20000a5c = 2;
+ *(uint16_t*)0x20000a60 = 8;
+ *(uint16_t*)0x20000a62 = 1;
+ *(uint32_t*)0x20000a64 = -1;
+ *(uint16_t*)0x20000a68 = 8;
+ *(uint16_t*)0x20000a6a = 3;
+ *(uint32_t*)0x20000a6c = 0xeec;
+ *(uint16_t*)0x20000a70 = 8;
+ *(uint16_t*)0x20000a72 = 2;
+ *(uint32_t*)0x20000a74 = r[2];
+ *(uint64_t*)0x200000c8 = 0xf8;
+ *(uint64_t*)0x20000198 = 1;
+ *(uint64_t*)0x200001a0 = 0;
+ *(uint64_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001b0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000180ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1aa144a8177fc4c9a38171053370722822172fc9.c b/syzkaller-repros/linux/1aa144a8177fc4c9a38171053370722822172fc9.c
new file mode 100644
index 0000000..6066a17
--- /dev/null
+++ b/syzkaller-repros/linux/1aa144a8177fc4c9a38171053370722822172fc9.c
@@ -0,0 +1,2306 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ exit(1);
+ }
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1) {
+ return;
+ }
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_fchdir, -1);
+ break;
+ case 1:
+ *(uint64_t*)0x20000340 = 0x20000240;
+ *(uint16_t*)0x20000240 = 0x10;
+ *(uint16_t*)0x20000242 = 0;
+ *(uint32_t*)0x20000244 = 0;
+ *(uint32_t*)0x20000248 = 4;
+ *(uint32_t*)0x20000348 = 0xc;
+ *(uint64_t*)0x20000350 = 0;
+ *(uint64_t*)0x20000358 = 1;
+ *(uint64_t*)0x20000360 = 0;
+ *(uint64_t*)0x20000368 = 0;
+ *(uint32_t*)0x20000370 = 0;
+ syscall(__NR_sendmsg, -1, 0x20000340ul, 0x4000004ul);
+ break;
+ case 2:
+ memcpy((void*)0x200001c0, "./bus\000", 6);
+ res = syscall(__NR_open, 0x200001c0ul, 0x141042ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 3:
+ *(uint32_t*)0x20000980 = 8;
+ memcpy(
+ (void*)0x20000984,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
+ 4096);
+ *(uint16_t*)0x20001984 = 0;
+ syscall(__NR_write, r[0], 0x20000980ul, 0x10a9ul);
+ break;
+ case 4:
+ *(uint64_t*)0x200000c0 = 0;
+ syscall(__NR_sendfile, r[0], r[0], 0x200000c0ul, 0x8080fffffffeul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ for (procid = 0; procid < 6; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1b03ffc6e5ce26465bd3c655c7d209c0d51d6aed.c b/syzkaller-repros/linux/1b03ffc6e5ce26465bd3c655c7d209c0d51d6aed.c
new file mode 100644
index 0000000..ce70761
--- /dev/null
+++ b/syzkaller-repros/linux/1b03ffc6e5ce26465bd3c655c7d209c0d51d6aed.c
@@ -0,0 +1,187 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 3; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000100, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000100, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_mmap, 0x20ffb000, 0x3000, 1, 0x11, r[0], 0);
+ break;
+ case 2:
+ syscall(__NR_mmap, 0x20ffa000, 0x4000, 0, 0x9011, r[0], 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1b726c0f177e6d976c900f81cf6248473a582459.c b/syzkaller-repros/linux/1b726c0f177e6d976c900f81cf6248473a582459.c
new file mode 100644
index 0000000..2b1ef20
--- /dev/null
+++ b/syzkaller-repros/linux/1b726c0f177e6d976c900f81cf6248473a582459.c
@@ -0,0 +1,579 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/loop.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+struct fs_image_segment {
+ void* data;
+ uintptr_t size;
+ uintptr_t offset;
+};
+
+#define IMAGE_MAX_SEGMENTS 4096
+#define IMAGE_MAX_SIZE (129 << 20)
+
+#define sys_memfd_create 319
+
+static unsigned long fs_image_segment_check(unsigned long size,
+ unsigned long nsegs, long segments)
+{
+ unsigned long i;
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ if (nsegs > IMAGE_MAX_SEGMENTS)
+ nsegs = IMAGE_MAX_SEGMENTS;
+ for (i = 0; i < nsegs; i++) {
+ if (segs[i].size > IMAGE_MAX_SIZE)
+ segs[i].size = IMAGE_MAX_SIZE;
+ segs[i].offset %= IMAGE_MAX_SIZE;
+ if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
+ segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
+ if (size < segs[i].offset + segs[i].offset)
+ size = segs[i].offset + segs[i].offset;
+ }
+ if (size > IMAGE_MAX_SIZE)
+ size = IMAGE_MAX_SIZE;
+ return size;
+}
+
+static long syz_mount_image(volatile long fsarg, volatile long dir,
+ volatile unsigned long size,
+ volatile unsigned long nsegs,
+ volatile long segments, volatile long flags,
+ volatile long optsarg)
+{
+ char loopname[64], fs[32], opts[256];
+ int loopfd, err = 0, res = -1;
+ unsigned long i;
+ NONFAILING(size = fs_image_segment_check(size, nsegs, segments));
+ int memfd = syscall(sys_memfd_create, "syz_mount_image", 0);
+ if (memfd == -1) {
+ err = errno;
+ goto error;
+ }
+ if (ftruncate(memfd, size)) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ for (i = 0; i < nsegs; i++) {
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ int res1 = 0;
+ NONFAILING(res1 =
+ pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset));
+ if (res1 < 0) {
+ }
+ }
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
+ loopfd = open(loopname, O_RDWR);
+ if (loopfd == -1) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ if (errno != EBUSY) {
+ err = errno;
+ goto error_close_loop;
+ }
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ usleep(1000);
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ err = errno;
+ goto error_close_loop;
+ }
+ }
+ mkdir((char*)dir, 0777);
+ memset(fs, 0, sizeof(fs));
+ NONFAILING(strncpy(fs, (char*)fsarg, sizeof(fs) - 1));
+ memset(opts, 0, sizeof(opts));
+ NONFAILING(strncpy(opts, (char*)optsarg, sizeof(opts) - 32));
+ if (strcmp(fs, "iso9660") == 0) {
+ flags |= MS_RDONLY;
+ } else if (strncmp(fs, "ext", 3) == 0) {
+ if (strstr(opts, "errors=panic") || strstr(opts, "errors=remount-ro") == 0)
+ strcat(opts, ",errors=continue");
+ } else if (strcmp(fs, "xfs") == 0) {
+ strcat(opts, ",nouuid");
+ }
+ if (mount(loopname, (char*)dir, fs, flags, opts)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ res = 0;
+error_clear_loop:
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+error_close_loop:
+ close(loopfd);
+error_close_memfd:
+ close(memfd);
+error:
+ errno = err;
+ return res;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void reset_loop()
+{
+ char buf[64];
+ snprintf(buf, sizeof(buf), "/dev/loop%llu", procid);
+ int loopfd = open(buf, O_RDWR);
+ if (loopfd != -1) {
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ close(loopfd);
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ NONFAILING(memcpy((void*)0x20000540, "vfat\000", 5));
+ NONFAILING(memcpy((void*)0x200002c0, "./file0\000", 8));
+ NONFAILING(*(uint64_t*)0x20000140 = 0x20010000);
+ NONFAILING(memcpy((void*)0x20010000,
+ "\xeb\x3c\x90\x6d\x6b\x66\x73\x2e\x66\x61\x74\x00\x02\x04"
+ "\x01\x00\x02\x00\x02\x70\xff\xf8",
+ 22));
+ NONFAILING(*(uint64_t*)0x20000148 = 0x16);
+ NONFAILING(*(uint64_t*)0x20000150 = 0);
+ syz_mount_image(0x20000540, 0x200002c0, 0x4e004, 1, 0x20000140, 0, 0);
+ NONFAILING(memcpy((void*)0x20000200, "./file0\000", 8));
+ res = syscall(__NR_open, 0x20000200ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_fchdir, r[0]);
+ NONFAILING(memcpy((void*)0x200001c0, "./bus\000", 6));
+ res = syscall(__NR_open, 0x200001c0ul, 0x141042ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ NONFAILING(memcpy((void*)0x20000140, "./bus\000", 6));
+ res = syscall(__NR_creat, 0x20000140ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_ftruncate, r[2], 0x48280ul);
+ syscall(__NR_sendfile, r[1], r[1], 0ul, 0x8080fffffffeul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1c457b98011e518f9c572b37d18afff2576b9318.c b/syzkaller-repros/linux/1c457b98011e518f9c572b37d18afff2576b9318.c
new file mode 100644
index 0000000..858acea
--- /dev/null
+++ b/syzkaller-repros/linux/1c457b98011e518f9c572b37d18afff2576b9318.c
@@ -0,0 +1,426 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x200001c0 = 3;
+ syscall(__NR_ioctl, r[0], 0x541cul, 0x200001c0ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ *(uint8_t*)0x20000000 = 2;
+ *(uint16_t*)0x20000001 = 0;
+ *(uint16_t*)0x20000003 = 2;
+ *(uint16_t*)0x20000005 = 0;
+ *(uint16_t*)0x20000007 = 0;
+ *(uint16_t*)0x20000009 = 0;
+ syscall(__NR_ioctl, r[1], 0x541cul, 0x20000000ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1cac1604db07e1f41dc6c9e55489cf2eb5e06840.c b/syzkaller-repros/linux/1cac1604db07e1f41dc6c9e55489cf2eb5e06840.c
new file mode 100644
index 0000000..f3d297b
--- /dev/null
+++ b/syzkaller-repros/linux/1cac1604db07e1f41dc6c9e55489cf2eb5e06840.c
@@ -0,0 +1,218 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20001080 = 0;
+ *(uint32_t*)0x20001088 = 0;
+ *(uint64_t*)0x20001090 = 0x20001040;
+ *(uint64_t*)0x20001040 = 0x20000780;
+ *(uint32_t*)0x20000780 = 0x64;
+ *(uint8_t*)0x20000784 = 2;
+ *(uint8_t*)0x20000785 = 6;
+ *(uint16_t*)0x20000786 = 1;
+ *(uint32_t*)0x20000788 = 0;
+ *(uint32_t*)0x2000078c = 0;
+ *(uint8_t*)0x20000790 = 0;
+ *(uint8_t*)0x20000791 = 0;
+ *(uint16_t*)0x20000792 = htobe16(0);
+ *(uint16_t*)0x20000794 = 0x10;
+ *(uint16_t*)0x20000796 = 3;
+ memcpy((void*)0x20000798, "bitmap:port\000", 12);
+ *(uint16_t*)0x200007a4 = 5;
+ *(uint16_t*)0x200007a6 = 4;
+ *(uint8_t*)0x200007a8 = 0;
+ *(uint16_t*)0x200007ac = 9;
+ *(uint16_t*)0x200007ae = 2;
+ memcpy((void*)0x200007b0, "syz0\000", 5);
+ *(uint16_t*)0x200007b8 = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x200007ba, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200007bb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200007bb, 1, 7, 1);
+ *(uint16_t*)0x200007bc = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x200007be, 4, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200007bf, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200007bf, 0, 7, 1);
+ *(uint16_t*)0x200007c0 = htobe16(0);
+ *(uint16_t*)0x200007c4 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x200007c6, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200007c7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200007c7, 0, 7, 1);
+ *(uint16_t*)0x200007c8 = htobe16(0);
+ *(uint16_t*)0x200007cc = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200007ce, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200007cf, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200007cf, 0, 7, 1);
+ *(uint32_t*)0x200007d0 = htobe32(0x18);
+ *(uint16_t*)0x200007d4 = 5;
+ *(uint16_t*)0x200007d6 = 5;
+ *(uint8_t*)0x200007d8 = 0;
+ *(uint16_t*)0x200007dc = 5;
+ *(uint16_t*)0x200007de = 1;
+ *(uint8_t*)0x200007e0 = 7;
+ *(uint64_t*)0x20001048 = 0x64;
+ *(uint64_t*)0x20001098 = 1;
+ *(uint64_t*)0x200010a0 = 0;
+ *(uint64_t*)0x200010a8 = 0;
+ *(uint32_t*)0x200010b0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20001080ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/1e212c963d94ea545321e73abef1fda38bfea8dc.c b/syzkaller-repros/linux/1e212c963d94ea545321e73abef1fda38bfea8dc.c
new file mode 100644
index 0000000..7f6893c
--- /dev/null
+++ b/syzkaller-repros/linux/1e212c963d94ea545321e73abef1fda38bfea8dc.c
@@ -0,0 +1,65 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 0x15);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x20000100 = 2;
+ *(uint8_t*)0x20000101 = 2;
+ *(uint16_t*)0x20000102 = 0;
+ *(uint16_t*)0x20000104 = 0;
+ *(uint16_t*)0x20000106 = 0;
+ *(uint16_t*)0x20000108 = 0;
+ *(uint16_t*)0x2000010a = 0;
+ syscall(__NR_ioctl, r[0], 0x541cul, 0x20000100ul);
+ res = syz_open_dev(0xc, 4, 0x14);
+ if (res != -1)
+ r[1] = res;
+ *(uint8_t*)0x20000040 = 3;
+ *(uint8_t*)0x20000041 = 2;
+ *(uint16_t*)0x20000042 = 0;
+ *(uint16_t*)0x20000044 = 0;
+ *(uint16_t*)0x20000046 = 0;
+ *(uint16_t*)0x20000048 = 0;
+ *(uint16_t*)0x2000004a = 0;
+ syscall(__NR_ioctl, r[1], 0x541cul, 0x20000040ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/21e6c5672c9cc31982e846c14c10ec3f6be48546.c b/syzkaller-repros/linux/21e6c5672c9cc31982e846c14c10ec3f6be48546.c
new file mode 100644
index 0000000..b716f8d
--- /dev/null
+++ b/syzkaller-repros/linux/21e6c5672c9cc31982e846c14c10ec3f6be48546.c
@@ -0,0 +1,818 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0x18, 1, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint16_t*)0x20000080 = 0x18;
+ *(uint32_t*)0x20000082 = 0;
+ *(uint16_t*)0x20000086 = 4;
+ *(uint8_t*)0x20000088 = 0xaa;
+ *(uint8_t*)0x20000089 = 0xaa;
+ *(uint8_t*)0x2000008a = 0xaa;
+ *(uint8_t*)0x2000008b = 0xaa;
+ *(uint8_t*)0x2000008c = 0xaa;
+ *(uint8_t*)0x2000008d = 0xa;
+ memcpy((void*)0x2000008e,
+ "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ syscall(__NR_connect, r[0], 0x20000080, 0x1e);
+ break;
+ case 2:
+ *(uint64_t*)0x20007b00 = 0;
+ *(uint32_t*)0x20007b08 = 0;
+ *(uint64_t*)0x20007b10 = 0;
+ *(uint64_t*)0x20007b18 = 0;
+ *(uint64_t*)0x20007b20 = 0;
+ *(uint64_t*)0x20007b28 = 0;
+ *(uint32_t*)0x20007b30 = 0;
+ *(uint32_t*)0x20007b38 = 0x12;
+ *(uint64_t*)0x20007b40 = 0;
+ *(uint32_t*)0x20007b48 = 0;
+ *(uint64_t*)0x20007b50 = 0;
+ *(uint64_t*)0x20007b58 = 0;
+ *(uint64_t*)0x20007b60 = 0;
+ *(uint64_t*)0x20007b68 = 0;
+ *(uint32_t*)0x20007b70 = 0;
+ *(uint32_t*)0x20007b78 = 4;
+ *(uint64_t*)0x20007b80 = 0;
+ *(uint32_t*)0x20007b88 = 0;
+ *(uint64_t*)0x20007b90 = 0;
+ *(uint64_t*)0x20007b98 = 0;
+ *(uint64_t*)0x20007ba0 = 0;
+ *(uint64_t*)0x20007ba8 = 0;
+ *(uint32_t*)0x20007bb0 = 0;
+ *(uint32_t*)0x20007bb8 = 0xffffff47;
+ *(uint64_t*)0x20007bc0 = 0;
+ *(uint32_t*)0x20007bc8 = 0;
+ *(uint64_t*)0x20007bd0 = 0;
+ *(uint64_t*)0x20007bd8 = 0;
+ *(uint64_t*)0x20007be0 = 0;
+ *(uint64_t*)0x20007be8 = 0;
+ *(uint32_t*)0x20007bf0 = 0;
+ *(uint32_t*)0x20007bf8 = 6;
+ *(uint64_t*)0x20007c00 = 0;
+ *(uint32_t*)0x20007c08 = 0;
+ *(uint64_t*)0x20007c10 = 0;
+ *(uint64_t*)0x20007c18 = 0;
+ *(uint64_t*)0x20007c20 = 0;
+ *(uint64_t*)0x20007c28 = 0;
+ *(uint32_t*)0x20007c30 = 0;
+ *(uint32_t*)0x20007c38 = 3;
+ *(uint64_t*)0x20007c40 = 0;
+ *(uint32_t*)0x20007c48 = 0;
+ *(uint64_t*)0x20007c50 = 0;
+ *(uint64_t*)0x20007c58 = 0;
+ *(uint64_t*)0x20007c60 = 0;
+ *(uint64_t*)0x20007c68 = 0;
+ *(uint32_t*)0x20007c70 = 0;
+ *(uint32_t*)0x20007c78 = 0x20;
+ *(uint64_t*)0x20007c80 = 0;
+ *(uint32_t*)0x20007c88 = 0;
+ *(uint64_t*)0x20007c90 = 0;
+ *(uint64_t*)0x20007c98 = 0;
+ *(uint64_t*)0x20007ca0 = 0;
+ *(uint64_t*)0x20007ca8 = 0;
+ *(uint32_t*)0x20007cb0 = 0;
+ *(uint32_t*)0x20007cb8 = 0x8000;
+ syscall(__NR_recvmmsg, r[0], 0x20007b00, 7, 0x10101, 0);
+ break;
+ case 3:
+ syscall(__NR_sendto, r[0], 0, 0, 0, 0, 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/222516e6278a2c349a7e3b662c1a31831f5c85e8.c b/syzkaller-repros/linux/222516e6278a2c349a7e3b662c1a31831f5c85e8.c
new file mode 100644
index 0000000..a0f38ba
--- /dev/null
+++ b/syzkaller-repros/linux/222516e6278a2c349a7e3b662c1a31831f5c85e8.c
@@ -0,0 +1,284 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000440;
+ *(uint32_t*)0x20000440 = 0x54;
+ *(uint8_t*)0x20000444 = 2;
+ *(uint8_t*)0x20000445 = 6;
+ *(uint16_t*)0x20000446 = 1;
+ *(uint32_t*)0x20000448 = 0;
+ *(uint32_t*)0x2000044c = 0;
+ *(uint8_t*)0x20000450 = 0;
+ *(uint8_t*)0x20000451 = 0;
+ *(uint16_t*)0x20000452 = htobe16(0);
+ *(uint16_t*)0x20000454 = 9;
+ *(uint16_t*)0x20000456 = 2;
+ memcpy((void*)0x20000458, "syz2\000", 5);
+ *(uint16_t*)0x20000460 = 0xd;
+ *(uint16_t*)0x20000462 = 3;
+ memcpy((void*)0x20000464, "hash:net\000", 9);
+ *(uint16_t*)0x20000470 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000472, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 1, 7, 1);
+ *(uint16_t*)0x20000474 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000476, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000477, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000477, 0, 7, 1);
+ *(uint32_t*)0x20000478 = htobe32(3);
+ *(uint16_t*)0x2000047c = 5;
+ *(uint16_t*)0x2000047e = 1;
+ *(uint8_t*)0x20000480 = 7;
+ *(uint16_t*)0x20000484 = 5;
+ *(uint16_t*)0x20000486 = 4;
+ *(uint8_t*)0x20000488 = 0;
+ *(uint16_t*)0x2000048c = 5;
+ *(uint16_t*)0x2000048e = 5;
+ *(uint8_t*)0x20000490 = 2;
+ *(uint64_t*)0x200002c8 = 0x54;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 4ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000200 = 0;
+ *(uint32_t*)0x20000208 = 0;
+ *(uint64_t*)0x20000210 = 0x200001c0;
+ *(uint64_t*)0x200001c0 = 0x20000340;
+ *(uint32_t*)0x20000340 = 0x70;
+ *(uint8_t*)0x20000344 = 0xb;
+ *(uint8_t*)0x20000345 = 6;
+ *(uint16_t*)0x20000346 = 1;
+ *(uint32_t*)0x20000348 = 0;
+ *(uint32_t*)0x2000034c = 0;
+ *(uint8_t*)0x20000350 = 2;
+ *(uint8_t*)0x20000351 = 0;
+ *(uint16_t*)0x20000352 = htobe16(0);
+ *(uint16_t*)0x20000354 = 9;
+ *(uint16_t*)0x20000356 = 2;
+ memcpy((void*)0x20000358, "syz2\000", 5);
+ *(uint16_t*)0x20000360 = 5;
+ *(uint16_t*)0x20000362 = 1;
+ *(uint8_t*)0x20000364 = 7;
+ *(uint16_t*)0x20000368 = 0x48;
+ STORE_BY_BITMASK(uint16_t, , 0x2000036a, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000036b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000036b, 1, 7, 1);
+ *(uint16_t*)0x2000036c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000036e, 0x18, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000036f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000036f, 0, 7, 1);
+ *(uint64_t*)0x20000370 = htobe64(0xc7);
+ *(uint16_t*)0x20000378 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000037a, 0x18, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000037b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000037b, 0, 7, 1);
+ *(uint64_t*)0x2000037c = htobe64(1);
+ *(uint16_t*)0x20000384 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000386, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000387, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000387, 0, 7, 1);
+ *(uint32_t*)0x20000388 = htobe32(9);
+ *(uint16_t*)0x2000038c = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x2000038e, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000038f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000038f, 1, 7, 1);
+ *(uint16_t*)0x20000390 = 0x14;
+ STORE_BY_BITMASK(uint16_t, , 0x20000392, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000393, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000393, 0, 7, 1);
+ *(uint8_t*)0x20000394 = 0xfe;
+ *(uint8_t*)0x20000395 = 0x80;
+ *(uint8_t*)0x20000396 = 0;
+ *(uint8_t*)0x20000397 = 0;
+ *(uint8_t*)0x20000398 = 0;
+ *(uint8_t*)0x20000399 = 0;
+ *(uint8_t*)0x2000039a = 0;
+ *(uint8_t*)0x2000039b = 0;
+ *(uint8_t*)0x2000039c = 0;
+ *(uint8_t*)0x2000039d = 0;
+ *(uint8_t*)0x2000039e = 0;
+ *(uint8_t*)0x2000039f = 0;
+ *(uint8_t*)0x200003a0 = 0;
+ *(uint8_t*)0x200003a1 = 0;
+ *(uint8_t*)0x200003a2 = 0;
+ *(uint8_t*)0x200003a3 = 0x16;
+ *(uint16_t*)0x200003a4 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200003a6, 0x19, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200003a7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200003a7, 0, 7, 1);
+ *(uint64_t*)0x200003a8 = htobe64(8);
+ *(uint64_t*)0x200001c8 = 0x70;
+ *(uint64_t*)0x20000218 = 1;
+ *(uint64_t*)0x20000220 = 0;
+ *(uint64_t*)0x20000228 = 0;
+ *(uint32_t*)0x20000230 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000200ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_sendmsg, r[2], 0ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2294af0e015d1884b11f0d613be6c3d5585b0f2f.c b/syzkaller-repros/linux/2294af0e015d1884b11f0d613be6c3d5585b0f2f.c
new file mode 100644
index 0000000..85dc1d0
--- /dev/null
+++ b/syzkaller-repros/linux/2294af0e015d1884b11f0d613be6c3d5585b0f2f.c
@@ -0,0 +1,933 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/loop.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+struct fs_image_segment {
+ void* data;
+ uintptr_t size;
+ uintptr_t offset;
+};
+
+#define IMAGE_MAX_SEGMENTS 4096
+#define IMAGE_MAX_SIZE (129 << 20)
+
+#define sys_memfd_create 319
+
+static unsigned long fs_image_segment_check(unsigned long size,
+ unsigned long nsegs, long segments)
+{
+ unsigned long i;
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ if (nsegs > IMAGE_MAX_SEGMENTS)
+ nsegs = IMAGE_MAX_SEGMENTS;
+ for (i = 0; i < nsegs; i++) {
+ if (segs[i].size > IMAGE_MAX_SIZE)
+ segs[i].size = IMAGE_MAX_SIZE;
+ segs[i].offset %= IMAGE_MAX_SIZE;
+ if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
+ segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
+ if (size < segs[i].offset + segs[i].offset)
+ size = segs[i].offset + segs[i].offset;
+ }
+ if (size > IMAGE_MAX_SIZE)
+ size = IMAGE_MAX_SIZE;
+ return size;
+}
+
+static long syz_mount_image(volatile long fsarg, volatile long dir,
+ volatile unsigned long size,
+ volatile unsigned long nsegs,
+ volatile long segments, volatile long flags,
+ volatile long optsarg)
+{
+ char loopname[64], fs[32], opts[256];
+ int loopfd, err = 0, res = -1;
+ unsigned long i;
+ NONFAILING(size = fs_image_segment_check(size, nsegs, segments));
+ int memfd = syscall(sys_memfd_create, "syz_mount_image", 0);
+ if (memfd == -1) {
+ err = errno;
+ goto error;
+ }
+ if (ftruncate(memfd, size)) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ for (i = 0; i < nsegs; i++) {
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ int res1 = 0;
+ NONFAILING(res1 =
+ pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset));
+ if (res1 < 0) {
+ }
+ }
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
+ loopfd = open(loopname, O_RDWR);
+ if (loopfd == -1) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ if (errno != EBUSY) {
+ err = errno;
+ goto error_close_loop;
+ }
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ usleep(1000);
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ err = errno;
+ goto error_close_loop;
+ }
+ }
+ mkdir((char*)dir, 0777);
+ memset(fs, 0, sizeof(fs));
+ NONFAILING(strncpy(fs, (char*)fsarg, sizeof(fs) - 1));
+ memset(opts, 0, sizeof(opts));
+ NONFAILING(strncpy(opts, (char*)optsarg, sizeof(opts) - 32));
+ if (strcmp(fs, "iso9660") == 0) {
+ flags |= MS_RDONLY;
+ } else if (strncmp(fs, "ext", 3) == 0) {
+ if (strstr(opts, "errors=panic") || strstr(opts, "errors=remount-ro") == 0)
+ strcat(opts, ",errors=continue");
+ } else if (strcmp(fs, "xfs") == 0) {
+ strcat(opts, ",nouuid");
+ }
+ if (mount(loopname, (char*)dir, fs, flags, opts)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ res = 0;
+error_clear_loop:
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+error_close_loop:
+ close(loopfd);
+error_close_memfd:
+ close(memfd);
+error:
+ errno = err;
+ return res;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ NONFAILING(memcpy((void*)0x20000540, "vfat\000", 5));
+ NONFAILING(memcpy((void*)0x200002c0, "./file0\000", 8));
+ NONFAILING(*(uint64_t*)0x20000140 = 0x20010000);
+ NONFAILING(memcpy((void*)0x20010000,
+ "\xeb\x3c\x90\x6d\x6b\x66\x73\x2e\x66\x61\x74\x00\x02\x04"
+ "\x01\x00\x02\x00\x02\x70\xff\xf8",
+ 22));
+ NONFAILING(*(uint64_t*)0x20000148 = 0x16);
+ NONFAILING(*(uint64_t*)0x20000150 = 0);
+ syz_mount_image(0x20000540, 0x200002c0, 0x4e004, 1, 0x20000140, 0, 0);
+ NONFAILING(memcpy((void*)0x20000200, "./file0\000", 8));
+ res = syscall(__NR_open, 0x20000200ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_fchdir, r[0]);
+ res = syscall(__NR_socket, 0xaul, 5ul, 0xfc);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_ioctl, -1, 0x890dul, 0ul);
+ syscall(__NR_getsockopt, r[1], 1ul, 0x37ul, 0ul, 0ul);
+ syscall(__NR_getsockopt, r[1], 0x84ul, 0xaul, 0ul, 0ul);
+ NONFAILING(memcpy((void*)0x20000140, "./bus\000", 6));
+ res = syscall(__NR_creat, 0x20000140ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_ftruncate, r[2], 0x48280ul);
+ syscall(__NR_sendfile, -1, -1, 0ul, 0x8080fffffffeul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ install_segv_handler();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/22ecdb4eef6e9b264b7a96d8e7ae1cde81d7958c.c b/syzkaller-repros/linux/22ecdb4eef6e9b264b7a96d8e7ae1cde81d7958c.c
new file mode 100644
index 0000000..fd7a4d1
--- /dev/null
+++ b/syzkaller-repros/linux/22ecdb4eef6e9b264b7a96d8e7ae1cde81d7958c.c
@@ -0,0 +1,355 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20003ac0 = 0;
+ *(uint32_t*)0x20003ac8 = 0;
+ *(uint64_t*)0x20003ad0 = 0x20003a80;
+ *(uint64_t*)0x20003a80 = 0x20003940;
+ *(uint32_t*)0x20003940 = 0x14;
+ *(uint16_t*)0x20003944 = 0x10;
+ *(uint16_t*)0x20003946 = 1;
+ *(uint32_t*)0x20003948 = 0;
+ *(uint32_t*)0x2000394c = 0;
+ *(uint8_t*)0x20003950 = 0;
+ *(uint8_t*)0x20003951 = 0;
+ *(uint16_t*)0x20003952 = htobe16(0xa);
+ *(uint32_t*)0x20003954 = 0xe0;
+ *(uint8_t*)0x20003958 = 0x18;
+ *(uint8_t*)0x20003959 = 0xa;
+ *(uint16_t*)0x2000395a = 0x101;
+ *(uint32_t*)0x2000395c = 0;
+ *(uint32_t*)0x20003960 = 0;
+ *(uint8_t*)0x20003964 = 1;
+ *(uint8_t*)0x20003965 = 0;
+ *(uint16_t*)0x20003966 = htobe16(0);
+ *(uint16_t*)0x20003968 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000396a, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000396b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000396b, 0, 7, 1);
+ *(uint32_t*)0x2000396c = htobe32(3);
+ *(uint16_t*)0x20003970 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20003972, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003973, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003973, 0, 7, 1);
+ *(uint64_t*)0x20003974 = htobe64(1);
+ *(uint16_t*)0x2000397c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000397e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000397f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000397f, 0, 7, 1);
+ *(uint32_t*)0x20003980 = htobe32(1);
+ *(uint16_t*)0x20003984 = 0xa4;
+ STORE_BY_BITMASK(uint16_t, , 0x20003986, 3, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003987, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003987, 1, 7, 1);
+ *(uint16_t*)0x20003988 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000398a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000398b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000398b, 0, 7, 1);
+ *(uint32_t*)0x2000398c = htobe32(0);
+ *(uint16_t*)0x20003990 = 0x68;
+ STORE_BY_BITMASK(uint16_t, , 0x20003992, 3, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003993, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003993, 1, 7, 1);
+ *(uint16_t*)0x20003994 = 0x14;
+ *(uint16_t*)0x20003996 = 1;
+ memcpy((void*)0x20003998, "veth0_vlan\000\000\000\000\000\000", 16);
+ *(uint16_t*)0x200039a8 = 0x14;
+ *(uint16_t*)0x200039aa = 1;
+ memcpy((void*)0x200039ac, "bond0\000\000\000\000\000\000\000\000\000\000\000",
+ 16);
+ *(uint16_t*)0x200039bc = 0x14;
+ *(uint16_t*)0x200039be = 1;
+ memcpy((void*)0x200039c0, "ip6gretap0\000\000\000\000\000\000", 16);
+ *(uint16_t*)0x200039d0 = 0x14;
+ *(uint16_t*)0x200039d2 = 1;
+ memcpy((void*)0x200039d4, "gretap0\000\000\000\000\000\000\000\000\000", 16);
+ *(uint16_t*)0x200039e4 = 0x14;
+ *(uint16_t*)0x200039e6 = 1;
+ memcpy((void*)0x200039e8,
+ "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint16_t*)0x200039f8 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200039fa, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200039fb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200039fb, 0, 7, 1);
+ *(uint32_t*)0x200039fc = htobe32(5);
+ *(uint16_t*)0x20003a00 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20003a02, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a03, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a03, 0, 7, 1);
+ *(uint32_t*)0x20003a04 = htobe32(0);
+ *(uint16_t*)0x20003a08 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20003a0a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a0b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a0b, 0, 7, 1);
+ *(uint32_t*)0x20003a0c = htobe32(0);
+ *(uint16_t*)0x20003a10 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20003a12, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a13, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a13, 0, 7, 1);
+ *(uint32_t*)0x20003a14 = htobe32(0);
+ *(uint16_t*)0x20003a18 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20003a1a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a1b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a1b, 0, 7, 1);
+ *(uint32_t*)0x20003a1c = htobe32(0);
+ *(uint16_t*)0x20003a20 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20003a22, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a23, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003a23, 0, 7, 1);
+ *(uint32_t*)0x20003a24 = htobe32(4);
+ *(uint16_t*)0x20003a28 = 9;
+ *(uint16_t*)0x20003a2a = 1;
+ memcpy((void*)0x20003a2c, "syz0\000", 5);
+ *(uint32_t*)0x20003a34 = 0x2c;
+ *(uint8_t*)0x20003a38 = 2;
+ *(uint8_t*)0x20003a39 = 0xa;
+ *(uint16_t*)0x20003a3a = 0x101;
+ *(uint32_t*)0x20003a3c = 0;
+ *(uint32_t*)0x20003a40 = 0;
+ *(uint8_t*)0x20003a44 = 0;
+ *(uint8_t*)0x20003a45 = 0;
+ *(uint16_t*)0x20003a46 = htobe16(1);
+ *(uint16_t*)0x20003a48 = 9;
+ *(uint16_t*)0x20003a4a = 1;
+ memcpy((void*)0x20003a4c, "syz0\000", 5);
+ *(uint16_t*)0x20003a54 = 9;
+ *(uint16_t*)0x20003a56 = 1;
+ memcpy((void*)0x20003a58, "syz0\000", 5);
+ *(uint32_t*)0x20003a60 = 0x14;
+ *(uint16_t*)0x20003a64 = 0x11;
+ *(uint16_t*)0x20003a66 = 1;
+ *(uint32_t*)0x20003a68 = 0;
+ *(uint32_t*)0x20003a6c = 0;
+ *(uint8_t*)0x20003a70 = 0;
+ *(uint8_t*)0x20003a71 = 0;
+ *(uint16_t*)0x20003a72 = htobe16(0xa);
+ *(uint64_t*)0x20003a88 = 0x134;
+ *(uint64_t*)0x20003ad8 = 1;
+ *(uint64_t*)0x20003ae0 = 0;
+ *(uint64_t*)0x20003ae8 = 0;
+ *(uint32_t*)0x20003af0 = 0x4000800;
+ syscall(__NR_sendmsg, r[0], 0x20003ac0ul, 0x42ul);
+ *(uint64_t*)0x20003e00 = 0;
+ *(uint32_t*)0x20003e08 = 0;
+ *(uint64_t*)0x20003e10 = 0x20003dc0;
+ *(uint64_t*)0x20003dc0 = 0x20000200;
+ *(uint32_t*)0x20000200 = 0x14;
+ *(uint16_t*)0x20000204 = 0x10;
+ *(uint16_t*)0x20000206 = 1;
+ *(uint32_t*)0x20000208 = 0;
+ *(uint32_t*)0x2000020c = 0;
+ *(uint8_t*)0x20000210 = 0;
+ *(uint8_t*)0x20000211 = 0;
+ *(uint16_t*)0x20000212 = htobe16(0xa);
+ *(uint32_t*)0x20000214 = 0x20;
+ *(uint8_t*)0x20000218 = 0;
+ *(uint8_t*)0x20000219 = 0xa;
+ *(uint16_t*)0x2000021a = 0x1405;
+ *(uint32_t*)0x2000021c = 0;
+ *(uint32_t*)0x20000220 = 0;
+ *(uint8_t*)0x20000224 = 1;
+ *(uint8_t*)0x20000225 = 0;
+ *(uint16_t*)0x20000226 = htobe16(0);
+ *(uint16_t*)0x20000228 = 9;
+ *(uint16_t*)0x2000022a = 1;
+ memcpy((void*)0x2000022c, "syz0\000", 5);
+ *(uint32_t*)0x20000234 = 0x58;
+ *(uint8_t*)0x20000238 = 0x16;
+ *(uint8_t*)0x20000239 = 0xa;
+ *(uint16_t*)0x2000023a = 1;
+ *(uint32_t*)0x2000023c = 0;
+ *(uint32_t*)0x20000240 = 0;
+ *(uint8_t*)0x20000244 = 1;
+ *(uint8_t*)0x20000245 = 0;
+ *(uint16_t*)0x20000246 = htobe16(0);
+ *(uint16_t*)0x20000248 = 9;
+ *(uint16_t*)0x2000024a = 1;
+ memcpy((void*)0x2000024c, "syz0\000", 5);
+ *(uint16_t*)0x20000254 = 9;
+ *(uint16_t*)0x20000256 = 2;
+ memcpy((void*)0x20000258, "syz2\000", 5);
+ *(uint16_t*)0x20000260 = 0x2c;
+ STORE_BY_BITMASK(uint16_t, , 0x20000262, 3, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000263, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000263, 1, 7, 1);
+ *(uint16_t*)0x20000264 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x20000266, 3, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000267, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000267, 1, 7, 1);
+ *(uint16_t*)0x20000268 = 0x14;
+ *(uint16_t*)0x2000026a = 1;
+ memcpy((void*)0x2000026c,
+ "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint16_t*)0x2000027c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000027e, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000027f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000027f, 0, 7, 1);
+ *(uint32_t*)0x20000280 = htobe32(0);
+ *(uint16_t*)0x20000284 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000286, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000287, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000287, 0, 7, 1);
+ *(uint32_t*)0x20000288 = htobe32(0);
+ *(uint32_t*)0x2000028c = 0x14;
+ *(uint16_t*)0x20000290 = 0x11;
+ *(uint16_t*)0x20000292 = 1;
+ *(uint32_t*)0x20000294 = 0;
+ *(uint32_t*)0x20000298 = 0;
+ *(uint8_t*)0x2000029c = 0;
+ *(uint8_t*)0x2000029d = 0;
+ *(uint16_t*)0x2000029e = htobe16(0xa);
+ *(uint64_t*)0x20003dc8 = 0xa0;
+ *(uint64_t*)0x20003e18 = 1;
+ *(uint64_t*)0x20003e20 = 0;
+ *(uint64_t*)0x20003e28 = 0;
+ *(uint32_t*)0x20003e30 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20003e00ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/24d6c3a58caeec00e7eb0194ec12b2ecc7099754.c b/syzkaller-repros/linux/24d6c3a58caeec00e7eb0194ec12b2ecc7099754.c
new file mode 100644
index 0000000..a899944
--- /dev/null
+++ b/syzkaller-repros/linux/24d6c3a58caeec00e7eb0194ec12b2ecc7099754.c
@@ -0,0 +1,490 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x18, 1, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20000240 = 0x18;
+ *(uint32_t*)0x20000242 = 0;
+ *(uint16_t*)0x20000246 = 1;
+ *(uint8_t*)0x20000248 = 0xaa;
+ *(uint8_t*)0x20000249 = 0xaa;
+ *(uint8_t*)0x2000024a = 0xaa;
+ *(uint8_t*)0x2000024b = 0xaa;
+ *(uint8_t*)0x2000024c = 0xaa;
+ *(uint8_t*)0x2000024d = 0x24;
+ memcpy((void*)0x2000024e,
+ "hsr0\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ syscall(__NR_connect, r[0], 0x20000240, 0x1e);
+ *(uint64_t*)0x200035c0 = 0;
+ *(uint32_t*)0x200035c8 = 0;
+ *(uint64_t*)0x200035d0 = 0;
+ *(uint64_t*)0x200035d8 = 0;
+ *(uint64_t*)0x200035e0 = 0;
+ *(uint64_t*)0x200035e8 = 0;
+ *(uint32_t*)0x200035f0 = 0;
+ *(uint32_t*)0x200035f8 = 0;
+ *(uint64_t*)0x20003600 = 0;
+ *(uint32_t*)0x20003608 = 0;
+ *(uint64_t*)0x20003610 = 0;
+ *(uint64_t*)0x20003618 = 0;
+ *(uint64_t*)0x20003620 = 0;
+ *(uint64_t*)0x20003628 = 0;
+ *(uint32_t*)0x20003630 = 0;
+ *(uint32_t*)0x20003638 = 0;
+ *(uint64_t*)0x20003640 = 0;
+ *(uint32_t*)0x20003648 = 0;
+ *(uint64_t*)0x20003650 = 0;
+ *(uint64_t*)0x20003658 = 0;
+ *(uint64_t*)0x20003660 = 0;
+ *(uint64_t*)0x20003668 = 0;
+ *(uint32_t*)0x20003670 = 0;
+ *(uint32_t*)0x20003678 = 0;
+ syscall(__NR_sendmmsg, r[0], 0x200035c0, 3, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/28fe34b65b6b1224d5f9f1abbc49011dc44f1487.c b/syzkaller-repros/linux/28fe34b65b6b1224d5f9f1abbc49011dc44f1487.c
new file mode 100644
index 0000000..4772d0b
--- /dev/null
+++ b/syzkaller-repros/linux/28fe34b65b6b1224d5f9f1abbc49011dc44f1487.c
@@ -0,0 +1,846 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 0x14);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x5608ul, 0);
+ close_fds();
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ install_segv_handler();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/290dd60a3f01510810de93fb9825a761a4b99391.c b/syzkaller-repros/linux/290dd60a3f01510810de93fb9825a761a4b99391.c
new file mode 100644
index 0000000..ccd7828
--- /dev/null
+++ b/syzkaller-repros/linux/290dd60a3f01510810de93fb9825a761a4b99391.c
@@ -0,0 +1,847 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0xaul, 0x80002ul, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0x400;
+ syscall(__NR_setsockopt, r[0], 0x11ul, 0x67ul, 0x20000040ul, 4ul);
+ res = syscall(__NR_socket, 2ul, 2ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x20000000 = 2;
+ *(uint16_t*)0x20000002 = htobe16(0x4e22);
+ *(uint32_t*)0x20000004 = htobe32(0);
+ syscall(__NR_bind, r[1], 0x20000000ul, 0x10ul);
+ *(uint16_t*)0x20000080 = 0xa;
+ *(uint16_t*)0x20000082 = htobe16(0);
+ *(uint32_t*)0x20000084 = htobe32(0);
+ *(uint8_t*)0x20000088 = 0xfe;
+ *(uint8_t*)0x20000089 = 0x80;
+ *(uint8_t*)0x2000008a = 0;
+ *(uint8_t*)0x2000008b = 0;
+ *(uint8_t*)0x2000008c = 0;
+ *(uint8_t*)0x2000008d = 0;
+ *(uint8_t*)0x2000008e = 0;
+ *(uint8_t*)0x2000008f = 0;
+ *(uint8_t*)0x20000090 = 0;
+ *(uint8_t*)0x20000091 = 0;
+ *(uint8_t*)0x20000092 = 0;
+ *(uint8_t*)0x20000093 = 0;
+ *(uint8_t*)0x20000094 = 0;
+ *(uint8_t*)0x20000095 = 0;
+ *(uint8_t*)0x20000096 = 0;
+ *(uint8_t*)0x20000097 = 0xaa;
+ *(uint32_t*)0x20000098 = 4;
+ syscall(__NR_connect, r[0], 0x20000080ul, 0x1cul);
+ memcpy(
+ (void*)0x20000600,
+ "\xc6\x7b\xf2\xac\x57\x90\xad\x79\x88\x32\x52\x8a\xfd\x13\x1c\xdf\x48\x04"
+ "\xcf\x48\x54\x59\x53\x51\xc4\x84\xe7\x61\x33\xf7\x3a\xd4\x30\xc9\x2d\xfb"
+ "\x94\xe5\x9e\x28\x43\x20\x27\xf3\x97\x81\xe5\xb6\xed\x85\xf5\x21\x82\x47"
+ "\x43\xe1\xc0\x22\xc4\xb8\x38\x25\xe6\x0c\x1d\xf0\x52\xb0\xad\xcd\x5e\x34"
+ "\xa4\xca\x8b\x39\x18\x42\x24\xe7\x9f\x13\x18\x1f\x21\x2c\x74\x30\xb0\x28"
+ "\xf2\x6d\x5a\xfe\xb9\x01\xb9\x43\x11\xb4\x53\x66\x74\x29\x27\xb8\xf2\xcb"
+ "\x3f\x9e\xaa\xc5\xe8\xbe\x7f\x3e\xd7\x01\xe6\x4b\x23\xc7\x3d\x72\xa2\xf9"
+ "\x8d\x0b\xb6\xc2\x33\xf2\x48\xb6\x7a\x47\xa0\xeb\xd0\x7a\x35\xe5\x1d\xa8"
+ "\x4a\x49\x44\x3f\xbe\xd3\xeb\xbf\xc4\xb6\xd7\xef\x21\xeb\x1e\x6a\xd0\x82"
+ "\x8e\xd4\x10\x6c\x0a\x2e\xfe\x82\x7c\x77\x07\x44\x42\xa3\xed\x0d\x62\x05"
+ "\x9b\x56\xb6\x7c\xb6\x1e\x56\x19\x3d\xb3\x03\xab\x7d\x0d\xd5\xd7\x78\x16"
+ "\xc5\x1a\x0d\x42\x22\xee\xa6\x31\x8f\xa0\x24\x7a\x7d\x21\xa3\xc1\x00\x92"
+ "\x41\x17\xb2\x75\x9a\xf3\x79\x31\x2e\xef\x20\xa9\x21\x2a\x28\x71\xee\x3f"
+ "\x3f\xbf\x85\xb6\x1e\x4f\xce\xce\x2c\x87\xd0\x40\x8f\xc4\x6b\x7d\xeb\xd8"
+ "\x84\xa9\xd2\x98\x92\x3e\x73\x27\x99\x22\xe7\x84\xd0\x56\x03\x01\x8e\x62"
+ "\x0f\x30\xfa\xce\x82\x95\xb2\xad\x56\xbf\xea\xd0\x2f\x12\x01\xa3\x9c\xa5"
+ "\x58\xa2\x9f\xe8\x3a\x61\xc7\x7c\xb5\xb9\x22\xfe\x1b\xc8\x73\x63\xf4\x1c"
+ "\xd6\xe2\x49\x1c\x5f\x8c\x39\xc8\x06\x9d\xbb\xa4\xcc\x6e\x23\x1f\x37\xd5"
+ "\x3f\x8f\x3d\x2f\xe8\x77\xd3\xcb\xc7\x5a\x2d\xf6\x12\xd7\x5b\x9f\x1e\xa4"
+ "\x94\x70\x2a\x65\x8d\x81\x0a\x72\x57\xd2\x3f\x0e\xe8\x55\xbe\x69\x4a\x5a"
+ "\xab\x0b\x84\xa0\xe9\xae\x50\x5d\x1a\x24\x02\xa4\x53\x7d\xee\xdc\x26\x4b"
+ "\xe3\xde\xdc\x6c\x47\x07\x76\x67\x3b\x45\x2d\x80\xa7\x5e\xfa\x54\x17\x30"
+ "\x19\x91\x10\xa3\x32\xfa\x9d\x24\xf5\x9d\x22\xb8\xf1\xc6\x3f\xcd\x41\xc1"
+ "\x3d\x2b\x2f\xee\xb6\xa2\x68\xfa\xa7\x90\x18\x74\x9b\xc4\x53\x55\x13\x21"
+ "\xfa\xc1\x05\x7e\x81\x0c\x50\x97\xce\xf7\x55\xbc\xc9\xae\x2f\x78\x12\x40"
+ "\x50\xc8\x9f\x7f\xdd\xf5\xe0\x65\x61\xb9\x24\xee\x06\x2a\x04\x0d\x00\xe3"
+ "\x1c\xca\xaa\x11\x9a\x08\x5a\xcc\x4a\x5a\xad\xbd\xbb\x09\xf7\x5a\xf5\x2c"
+ "\x47\x14\x62\xd5\xfc\xdf\xd2\xfa\xdb\x9e\x7d\x0b\xa0\xd4\x9b\x72\x58\xba"
+ "\xed\x5b\xd9\x43\xf6\xfb\xb6\xa9\x31\x33\x39\xae\x57\xc4\x97\x57\x36\x7c"
+ "\xb5\xc4\xcc\xcf\xd5\x69\xfb\xa0\x8e\xbd\x2f\xfc\x89\x53\x9c\xa9\x38\x13"
+ "\xe7\xa3\x55\xd9\xa5\x4f\xfc\xee\x8a\x19\x41\xfb\xf9\xb6\x88\x03\x0e\x86"
+ "\x40\x61\xc2\x27\x9d\x41\x28\x64\x99\xcb\xf1\x4a\xe6\x0d\x18\x72\x96\x12"
+ "\xcd\x62\x87\xf3\x7c\xb1\x16\x97\xd7\xf9\xa8\x5d\x99\x25\xc4\x8a\x51\x2a"
+ "\x50\x5b\xff\xbb\x1f\x14\xc3\x1b\xdb\x93\x87\xaf\x73\xf3\x72\x04\x83\xb2"
+ "\x2f\xcb\x1d\x1c\xa3\x7c\xf0\x8a\x94\x27\x52\xa0\xd6\x0f\x56\x3d\xaf\x11"
+ "\xbb\x0f\xdf\x93\x6d\xb7\x97\x24\x83\x80\x26\x47\x20\x96\x8a\xf1\xa6\x31"
+ "\xfc\x4d\x3e\x7a\x60\xc2\x22\x34\x8c\x6c\x88\xbe\x8c\x70\x62\x68\x80\xbf"
+ "\x0c\x4f\x56\xff\x9d\x2d\x93\x85\xaa\x4a\xf2\x54\xd2\xc6\x82\x7c\x00\x58"
+ "\x0f\x66\xa9\xdc\x3f\x48\x0d\xd8\xce\xdd\x2a\x58\xb9\x0b\xe2\xf5\xc3\x0d"
+ "\x56\xcc\x65\x0b\x76\x59\xe4\xf5\x35\x78\x50\xc0\xc3\x95\x5a\x73\x73\x17"
+ "\x37\x91\x7e\x27\xc9\x85\xcb\x01\xbc\x1e\xd8\x03\xb2\xb1\xf9\xbc\xec\x38"
+ "\x00\x49\x99\x96\x12\x4a\xfd\x6b\x82\x90\xb2\x68\x02\xf7\x06\xff\x49\xb6"
+ "\x2d\xe0\xec\x0c\xca\x3a\xc5\x1d\xcb\xf0\x65\xac\x20\x0b\xe0\xb1\x41\xa6"
+ "\xa0\x56\x3d\x6a\xd2\xe0\x88\x38\x9f\xa4\xb6\x93\x39\xd5\x05\x0e\x41\x4e"
+ "\x76\x8c\x95\xf2\x78\xcf\x7a\x53\x77\xd0\x77\x07\xd4\xf4\x16\x97\x96\xbf"
+ "\x97\xdf\x45\x76\x44\x7a\x54\x22\x70\xa0\xaf\x8b\xac\x82\x12\xac\x2b\x23"
+ "\xf6\x88\xb8\x6f\x50\xe2\xd1\xbf\x6c\x51\xd6\x87\x0a\x31\x09\x6b\xc4\x36"
+ "\xc2\x65\xe1\xf9\xea\x58\x33\x0b\x76\x81\x14\xc2\xd1\x2d\x07\x6b\xbe\x56"
+ "\xc9\xc5\x51\xe9\x7e\xe6\x3f\xef\x6a\xc6\x1d\x69\xf6\x97\xdf\x6e\xc1\xf4"
+ "\x9a\x36\x60\x86\x8a\x08\xed\xd2\x8f\xf1\x2e\x31\xcc\xab\x43\x76\xf8\x91"
+ "\x9e\x76\x8d\x70\xc9\x01\x91\x88\x80\x0b\x87\x78\x9d\xfd\x2a\x6a\xb3\xe9"
+ "\x7e\xe0\xfa\x03\xeb\xf9\x1f\x2c\x30\x46\x53\xc4\x41\xc8\x4e\xc9\xa0\x4a"
+ "\xdf\x54\x8a\xd4\xaa\x83\xf5\xb0\x05\xef\x24\xc8\xef\x86\xc4\xfc\x2c\x10"
+ "\xfd\x0b\xcb\x67\x38\xe9\xeb\x28\x9e\xcb\x42\x19\x37\xd6\x63\x3d\xab\xcc"
+ "\xa4\x13\x6a\x71\xf1\x68\xb0\xc9\xd7\xd3\xd2\x5c\xc3\x33\x9e\xa0\x01\xa1"
+ "\x7a\xea\x7f\x73\xd7\xac\xa7\x70\xe3\xc6\x55\xd4\x4e\xf1\x95\xc3\x55\x2c"
+ "\xb7\x8a\x5c\xf5\xe7\xbb\x4f\x03\x11\x3c\x38\xc4\x52\xef\x93\x32\xe6",
+ 1025);
+ *(uint16_t*)0x200011c0 = 0xa;
+ *(uint16_t*)0x200011c2 = htobe16(0x4e22);
+ *(uint32_t*)0x200011c4 = htobe32(0);
+ *(uint8_t*)0x200011c8 = 0;
+ *(uint8_t*)0x200011c9 = 0;
+ *(uint8_t*)0x200011ca = 0;
+ *(uint8_t*)0x200011cb = 0;
+ *(uint8_t*)0x200011cc = 0;
+ *(uint8_t*)0x200011cd = 0;
+ *(uint8_t*)0x200011ce = 0;
+ *(uint8_t*)0x200011cf = 0;
+ *(uint8_t*)0x200011d0 = 0;
+ *(uint8_t*)0x200011d1 = 0;
+ *(uint8_t*)0x200011d2 = -1;
+ *(uint8_t*)0x200011d3 = -1;
+ *(uint32_t*)0x200011d4 = htobe32(0xe0000001);
+ *(uint32_t*)0x200011d8 = 0;
+ syscall(__NR_sendto, r[0], 0x20000600ul, 0x401ul, 0ul, 0x200011c0ul, 0x1cul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/29fbc1ae06c54940ceeab87c4debcc81108829f4.c b/syzkaller-repros/linux/29fbc1ae06c54940ceeab87c4debcc81108829f4.c
new file mode 100644
index 0000000..3584824
--- /dev/null
+++ b/syzkaller-repros/linux/29fbc1ae06c54940ceeab87c4debcc81108829f4.c
@@ -0,0 +1,1921 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static long syz_genetlink_get_family_id(volatile long name)
+{
+ char buf[512] = {0};
+ struct nlmsghdr* hdr = (struct nlmsghdr*)buf;
+ struct genlmsghdr* genlhdr = (struct genlmsghdr*)NLMSG_DATA(hdr);
+ struct nlattr* attr = (struct nlattr*)(genlhdr + 1);
+ hdr->nlmsg_len =
+ sizeof(*hdr) + sizeof(*genlhdr) + sizeof(*attr) + GENL_NAMSIZ;
+ hdr->nlmsg_type = GENL_ID_CTRL;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ genlhdr->cmd = CTRL_CMD_GETFAMILY;
+ attr->nla_type = CTRL_ATTR_FAMILY_NAME;
+ attr->nla_len = sizeof(*attr) + GENL_NAMSIZ;
+ NONFAILING(strncpy((char*)(attr + 1), (char*)name, GENL_NAMSIZ));
+ struct iovec iov = {hdr, hdr->nlmsg_len};
+ struct sockaddr_nl addr = {0};
+ addr.nl_family = AF_NETLINK;
+ int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (fd == -1) {
+ return -1;
+ }
+ struct msghdr msg = {&addr, sizeof(addr), &iov, 1, NULL, 0, 0};
+ if (sendmsg(fd, &msg, 0) == -1) {
+ close(fd);
+ return -1;
+ }
+ ssize_t n = recv(fd, buf, sizeof(buf), 0);
+ close(fd);
+ if (n <= 0) {
+ return -1;
+ }
+ if (hdr->nlmsg_type != GENL_ID_CTRL) {
+ return -1;
+ }
+ for (; (char*)attr < buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID)
+ return *(uint16_t*)(attr + 1);
+ }
+ return -1;
+}
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[15] = {0xffffffffffffffff,
+ 0x0,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0x0,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0x0,
+ 0x0,
+ 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[0] = res;
+ NONFAILING(*(uint64_t*)0x20000180 = 0);
+ NONFAILING(*(uint32_t*)0x20000188 = 0);
+ NONFAILING(*(uint64_t*)0x20000190 = 0x20000000);
+ NONFAILING(*(uint64_t*)0x20000000 = 0x20000080);
+ NONFAILING(*(uint32_t*)0x20000080 = 0x48);
+ NONFAILING(*(uint16_t*)0x20000084 = 0x23);
+ NONFAILING(*(uint16_t*)0x20000086 = 0x847);
+ NONFAILING(*(uint32_t*)0x20000088 = 0);
+ NONFAILING(*(uint32_t*)0x2000008c = 0);
+ NONFAILING(*(uint8_t*)0x20000090 = 4);
+ NONFAILING(*(uint8_t*)0x20000091 = 0);
+ NONFAILING(*(uint16_t*)0x20000092 = 0);
+ NONFAILING(*(uint16_t*)0x20000094 = 0x34);
+ NONFAILING(*(uint16_t*)0x20000096 = 0x18);
+ NONFAILING(
+ memcpy((void*)0x20000098,
+ "\x01\x99\x92\x6d\x7b\x68\x19\x9f\x29\x71\xc6\xcc\x6b\xd0\xd0\xcb"
+ "\x0e\x69\x44\x21\xcf\x75\x5f\x6a\x84\xc9\x60\x22\x40\x90\x1a\x21"
+ "\xf6\x11\x5b\x4a\xc9\x58\xfa\xc8\x5c\xf8\xb1\xb1\xab",
+ 45));
+ NONFAILING(*(uint64_t*)0x20000008 = 0x48);
+ NONFAILING(*(uint64_t*)0x20000198 = 1);
+ NONFAILING(*(uint64_t*)0x200001a0 = 0);
+ NONFAILING(*(uint64_t*)0x200001a8 = 0);
+ NONFAILING(*(uint32_t*)0x200001b0 = 0);
+ syscall(__NR_sendmsg, r[0], 0x20000180ul, 0ul);
+ NONFAILING(memcpy((void*)0x20000080, "IPVS\000", 5));
+ res = syz_genetlink_get_family_id(0x20000080);
+ if (res != -1)
+ r[1] = res;
+ NONFAILING(*(uint64_t*)0x20000240 = 0);
+ NONFAILING(*(uint32_t*)0x20000248 = 0);
+ NONFAILING(*(uint64_t*)0x20000250 = 0x20000200);
+ NONFAILING(*(uint64_t*)0x20000200 = 0x200000c0);
+ NONFAILING(*(uint32_t*)0x200000c0 = 0xf0);
+ NONFAILING(*(uint16_t*)0x200000c4 = r[1]);
+ NONFAILING(*(uint16_t*)0x200000c6 = 4);
+ NONFAILING(*(uint32_t*)0x200000c8 = 0x70bd2a);
+ NONFAILING(*(uint32_t*)0x200000cc = 0x25dfdbfc);
+ NONFAILING(*(uint8_t*)0x200000d0 = 9);
+ NONFAILING(*(uint8_t*)0x200000d1 = 0);
+ NONFAILING(*(uint16_t*)0x200000d2 = 0);
+ NONFAILING(*(uint16_t*)0x200000d4 = 8);
+ NONFAILING(*(uint16_t*)0x200000d6 = 5);
+ NONFAILING(*(uint32_t*)0x200000d8 = 0x80);
+ NONFAILING(*(uint16_t*)0x200000dc = 8);
+ NONFAILING(*(uint16_t*)0x200000de = 4);
+ NONFAILING(*(uint32_t*)0x200000e0 = 8);
+ NONFAILING(*(uint16_t*)0x200000e4 = 0x1c);
+ NONFAILING(*(uint16_t*)0x200000e6 = 2);
+ NONFAILING(*(uint16_t*)0x200000e8 = 8);
+ NONFAILING(*(uint16_t*)0x200000ea = 0xb);
+ NONFAILING(*(uint16_t*)0x200000ec = 0xa);
+ NONFAILING(*(uint16_t*)0x200000f0 = 8);
+ NONFAILING(*(uint16_t*)0x200000f2 = 9);
+ NONFAILING(*(uint32_t*)0x200000f4 = 0xd4b);
+ NONFAILING(*(uint16_t*)0x200000f8 = 8);
+ NONFAILING(*(uint16_t*)0x200000fa = 6);
+ NONFAILING(*(uint32_t*)0x200000fc = 5);
+ NONFAILING(*(uint16_t*)0x20000100 = 0x50);
+ NONFAILING(*(uint16_t*)0x20000102 = 1);
+ NONFAILING(*(uint16_t*)0x20000104 = 0x14);
+ NONFAILING(*(uint16_t*)0x20000106 = 3);
+ NONFAILING(*(uint8_t*)0x20000108 = 0xac);
+ NONFAILING(*(uint8_t*)0x20000109 = 0x1e);
+ NONFAILING(*(uint8_t*)0x2000010a = 1);
+ NONFAILING(*(uint8_t*)0x2000010b = 1);
+ NONFAILING(*(uint16_t*)0x20000118 = 8);
+ NONFAILING(*(uint16_t*)0x2000011a = 0xb);
+ NONFAILING(memcpy((void*)0x2000011c, "sip\000", 4));
+ NONFAILING(*(uint16_t*)0x20000120 = 0x14);
+ NONFAILING(*(uint16_t*)0x20000122 = 3);
+ NONFAILING(*(uint8_t*)0x20000124 = 0);
+ NONFAILING(*(uint8_t*)0x20000125 = 0);
+ NONFAILING(*(uint8_t*)0x20000126 = 0);
+ NONFAILING(*(uint8_t*)0x20000127 = 0);
+ NONFAILING(*(uint8_t*)0x20000128 = 0);
+ NONFAILING(*(uint8_t*)0x20000129 = 0);
+ NONFAILING(*(uint8_t*)0x2000012a = 0);
+ NONFAILING(*(uint8_t*)0x2000012b = 0);
+ NONFAILING(*(uint8_t*)0x2000012c = 0);
+ NONFAILING(*(uint8_t*)0x2000012d = 0);
+ NONFAILING(*(uint8_t*)0x2000012e = 0);
+ NONFAILING(*(uint8_t*)0x2000012f = 0);
+ NONFAILING(*(uint8_t*)0x20000130 = 0);
+ NONFAILING(*(uint8_t*)0x20000131 = 0);
+ NONFAILING(*(uint8_t*)0x20000132 = 0);
+ NONFAILING(*(uint8_t*)0x20000133 = 0);
+ NONFAILING(*(uint16_t*)0x20000134 = 0x14);
+ NONFAILING(*(uint16_t*)0x20000136 = 3);
+ NONFAILING(*(uint32_t*)0x20000138 = htobe32(-1));
+ NONFAILING(*(uint16_t*)0x20000148 = 8);
+ NONFAILING(*(uint16_t*)0x2000014a = 9);
+ NONFAILING(*(uint32_t*)0x2000014c = 0x25);
+ NONFAILING(*(uint16_t*)0x20000150 = 0x14);
+ NONFAILING(*(uint16_t*)0x20000152 = 3);
+ NONFAILING(*(uint16_t*)0x20000154 = 8);
+ NONFAILING(*(uint16_t*)0x20000156 = 8);
+ NONFAILING(*(uint8_t*)0x20000158 = 0);
+ NONFAILING(*(uint16_t*)0x2000015c = 8);
+ NONFAILING(*(uint16_t*)0x2000015e = 4);
+ NONFAILING(*(uint16_t*)0x20000160 = 0);
+ NONFAILING(*(uint16_t*)0x20000164 = 8);
+ NONFAILING(*(uint16_t*)0x20000166 = 5);
+ NONFAILING(*(uint32_t*)0x20000168 = 0);
+ NONFAILING(*(uint16_t*)0x2000016c = 8);
+ NONFAILING(*(uint16_t*)0x2000016e = 6);
+ NONFAILING(*(uint32_t*)0x20000170 = 6);
+ NONFAILING(*(uint16_t*)0x20000174 = 0xc);
+ NONFAILING(*(uint16_t*)0x20000176 = 2);
+ NONFAILING(*(uint16_t*)0x20000178 = 8);
+ NONFAILING(*(uint16_t*)0x2000017a = 0xd);
+ NONFAILING(*(uint8_t*)0x2000017c = 0);
+ NONFAILING(*(uint16_t*)0x20000180 = 0x30);
+ NONFAILING(*(uint16_t*)0x20000182 = 3);
+ NONFAILING(*(uint16_t*)0x20000184 = 8);
+ NONFAILING(*(uint16_t*)0x20000186 = 1);
+ NONFAILING(*(uint32_t*)0x20000188 = 3);
+ NONFAILING(*(uint16_t*)0x2000018c = 0x14);
+ NONFAILING(*(uint16_t*)0x2000018e = 2);
+ NONFAILING(memcpy((void*)0x20000190,
+ "xfrm0\000\000\000\000\000\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint16_t*)0x200001a0 = 8);
+ NONFAILING(*(uint16_t*)0x200001a2 = 8);
+ NONFAILING(*(uint8_t*)0x200001a4 = 0x16);
+ NONFAILING(*(uint16_t*)0x200001a8 = 8);
+ NONFAILING(*(uint16_t*)0x200001aa = 1);
+ NONFAILING(*(uint32_t*)0x200001ac = 3);
+ NONFAILING(*(uint64_t*)0x20000208 = 0xf0);
+ NONFAILING(*(uint64_t*)0x20000258 = 1);
+ NONFAILING(*(uint64_t*)0x20000260 = 0);
+ NONFAILING(*(uint64_t*)0x20000268 = 0);
+ NONFAILING(*(uint32_t*)0x20000270 = 0);
+ syscall(__NR_sendmsg, r[0], 0x20000240ul, 0x48044ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ NONFAILING(memcpy((void*)0x200001c0,
+ "ip6tnl0\000\000\000\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint64_t*)0x200001d0 = 0x20000000);
+ NONFAILING(*(uint32_t*)0x20000000 = 0);
+ NONFAILING(*(uint32_t*)0x20000004 = 0);
+ NONFAILING(*(uint32_t*)0x20000008 = 0);
+ NONFAILING(*(uint16_t*)0x2000000c = 0);
+ NONFAILING(*(uint8_t*)0x2000000e = 0);
+ NONFAILING(*(uint8_t*)0x2000000f = 0);
+ NONFAILING(*(uint8_t*)0x20000010 = 0);
+ NONFAILING(*(uint8_t*)0x20000011 = 0);
+ NONFAILING(*(uint8_t*)0x20000012 = 0);
+ NONFAILING(*(uint8_t*)0x20000013 = 0);
+ NONFAILING(*(uint32_t*)0x20000014 = 0);
+ NONFAILING(*(uint32_t*)0x20000018 = 0);
+ NONFAILING(*(uint16_t*)0x2000001c = 0);
+ NONFAILING(*(uint8_t*)0x2000001e = 0);
+ NONFAILING(*(uint8_t*)0x2000001f = 0);
+ NONFAILING(*(uint32_t*)0x20000020 = 2);
+ NONFAILING(*(uint32_t*)0x20000024 = 0);
+ NONFAILING(*(uint32_t*)0x20000028 = 0);
+ syscall(__NR_ioctl, r[2], 0x89f3ul, 0x200001c0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[3] = res;
+ syscall(__NR_ioctl, r[3], 0x8b2aul, 0x20000040ul);
+ NONFAILING(memcpy((void*)0x200016c0,
+ "team0\000\000\000\000\000\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint32_t*)0x200016d0 = 0);
+ syscall(__NR_ioctl, r[3], 0x8933ul, 0x200016c0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[4] = res;
+ NONFAILING(*(uint32_t*)0x20000280 = 0x19d);
+ syscall(__NR_getsockname, -1, 0x20000080ul, 0x20000280ul);
+ NONFAILING(*(uint64_t*)0x20000180 = 0);
+ NONFAILING(*(uint32_t*)0x20000188 = 0);
+ NONFAILING(*(uint64_t*)0x20000190 = 0);
+ NONFAILING(*(uint64_t*)0x20000198 = 1);
+ NONFAILING(*(uint64_t*)0x200001a0 = 0);
+ NONFAILING(*(uint64_t*)0x200001a8 = 0);
+ NONFAILING(*(uint32_t*)0x200001b0 = 0);
+ syscall(__NR_sendmsg, r[4], 0x20000180ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[5] = res;
+ NONFAILING(
+ memcpy((void*)0x200003c0, "netdevsim0\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint32_t*)0x200003d0 = 0);
+ syscall(__NR_ioctl, r[5], 0x8933ul, 0x200003c0ul);
+ syscall(__NR_bind, -1, 0ul, 0ul);
+ syscall(__NR_getsockname, -1, 0x20000500ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[6] = res;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[7] = res;
+ res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ if (res != -1)
+ r[8] = res;
+ NONFAILING(*(uint64_t*)0x200001c0 = 0);
+ NONFAILING(*(uint32_t*)0x200001c8 = 0);
+ NONFAILING(*(uint64_t*)0x200001d0 = 0x20000180);
+ NONFAILING(*(uint64_t*)0x20000180 = 0);
+ NONFAILING(*(uint64_t*)0x20000188 = 0x3d2);
+ NONFAILING(*(uint64_t*)0x200001d8 = 1);
+ NONFAILING(*(uint64_t*)0x200001e0 = 0);
+ NONFAILING(*(uint64_t*)0x200001e8 = 0);
+ NONFAILING(*(uint32_t*)0x200001f0 = 0);
+ syscall(__NR_sendmsg, r[8], 0x200001c0ul, 0ul);
+ NONFAILING(*(uint32_t*)0x20000280 = 0x19d);
+ res = syscall(__NR_getsockname, r[8], 0x20000080ul, 0x20000280ul);
+ if (res != -1)
+ NONFAILING(r[9] = *(uint32_t*)0x20000084);
+ NONFAILING(*(uint64_t*)0x20000180 = 0);
+ NONFAILING(*(uint32_t*)0x20000188 = 0);
+ NONFAILING(*(uint64_t*)0x20000190 = 0x200000c0);
+ NONFAILING(*(uint64_t*)0x200000c0 = 0x20000000);
+ NONFAILING(memcpy((void*)0x20000000,
+ "\x34\x00\x00\x00\x10\x00\x01\x04\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00",
+ 20));
+ NONFAILING(*(uint32_t*)0x20000014 = r[9]);
+ NONFAILING(memcpy((void*)0x20000018,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x12\x00\x0c\x00"
+ "\x01\x00\x62\x72\x69\x64\x67\x65\x00\x00\x00\x02\x00",
+ 27));
+ NONFAILING(*(uint64_t*)0x200000c8 = 0x34);
+ NONFAILING(*(uint64_t*)0x20000198 = 1);
+ NONFAILING(*(uint64_t*)0x200001a0 = 0);
+ NONFAILING(*(uint64_t*)0x200001a8 = 0);
+ NONFAILING(*(uint32_t*)0x200001b0 = 0);
+ syscall(__NR_sendmsg, r[7], 0x20000180ul, 0ul);
+ res = syscall(__NR_socket, 0x200000000000011ul, 3ul, 0);
+ if (res != -1)
+ r[10] = res;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[11] = res;
+ NONFAILING(
+ memcpy((void*)0x200003c0, "netdevsim0\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint32_t*)0x200003d0 = 0);
+ res = syscall(__NR_ioctl, r[11], 0x8933ul, 0x200003c0ul);
+ if (res != -1)
+ NONFAILING(r[12] = *(uint32_t*)0x200003d0);
+ NONFAILING(*(uint16_t*)0x20000240 = 0x11);
+ NONFAILING(*(uint16_t*)0x20000242 = htobe16(0));
+ NONFAILING(*(uint32_t*)0x20000244 = r[12]);
+ NONFAILING(*(uint16_t*)0x20000248 = 1);
+ NONFAILING(*(uint8_t*)0x2000024a = 0);
+ NONFAILING(*(uint8_t*)0x2000024b = 6);
+ NONFAILING(*(uint8_t*)0x2000024c = 0);
+ NONFAILING(*(uint8_t*)0x2000024d = 0);
+ NONFAILING(*(uint8_t*)0x2000024e = 0);
+ NONFAILING(*(uint8_t*)0x2000024f = 0);
+ NONFAILING(*(uint8_t*)0x20000250 = 0);
+ NONFAILING(*(uint8_t*)0x20000251 = 0);
+ NONFAILING(*(uint8_t*)0x20000252 = 0);
+ NONFAILING(*(uint8_t*)0x20000253 = 0);
+ syscall(__NR_bind, r[10], 0x20000240ul, 0x14ul);
+ NONFAILING(*(uint32_t*)0x20000040 = 0x10eef0f1);
+ res = syscall(__NR_getsockname, r[10], 0x20000500ul, 0x20000040ul);
+ if (res != -1)
+ NONFAILING(r[13] = *(uint32_t*)0x20000504);
+ NONFAILING(*(uint64_t*)0x20000000 = 0);
+ NONFAILING(*(uint32_t*)0x20000008 = 0);
+ NONFAILING(*(uint64_t*)0x20000010 = 0x200000c0);
+ NONFAILING(*(uint64_t*)0x200000c0 = 0x20002700);
+ NONFAILING(*(uint32_t*)0x20002700 = 0x28);
+ NONFAILING(*(uint16_t*)0x20002704 = 0x10);
+ NONFAILING(*(uint16_t*)0x20002706 = 0x401);
+ NONFAILING(*(uint32_t*)0x20002708 = 0);
+ NONFAILING(*(uint32_t*)0x2000270c = 0);
+ NONFAILING(*(uint8_t*)0x20002710 = 0);
+ NONFAILING(*(uint8_t*)0x20002711 = 0);
+ NONFAILING(*(uint16_t*)0x20002712 = 0);
+ NONFAILING(*(uint32_t*)0x20002714 = r[13]);
+ NONFAILING(*(uint32_t*)0x20002718 = 0);
+ NONFAILING(*(uint32_t*)0x2000271c = 0);
+ NONFAILING(*(uint16_t*)0x20002720 = 8);
+ NONFAILING(*(uint16_t*)0x20002722 = 0xa);
+ NONFAILING(*(uint32_t*)0x20002724 = r[9]);
+ NONFAILING(*(uint64_t*)0x200000c8 = 0x28);
+ NONFAILING(*(uint64_t*)0x20000018 = 1);
+ NONFAILING(*(uint64_t*)0x20000020 = 0);
+ NONFAILING(*(uint64_t*)0x20000028 = 0);
+ NONFAILING(*(uint32_t*)0x20000030 = 0);
+ syscall(__NR_sendmsg, r[6], 0x20000000ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ syscall(__NR_getsockname, -1, 0ul, 0ul);
+ syscall(__NR_bind, -1, 0ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ syscall(__NR_ioctl, r[2], 0x8933ul, 0ul);
+ syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ res = syscall(__NR_socket, 0x200000000000011ul, 3ul, 0);
+ if (res != -1)
+ r[14] = res;
+ syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ syscall(__NR_bind, r[14], 0ul, 0ul);
+ syscall(__NR_ioctl, r[2], 0x8933ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2a8db7b9aa28c21f3b500e5781edcfd30a70dc4f.c b/syzkaller-repros/linux/2a8db7b9aa28c21f3b500e5781edcfd30a70dc4f.c
new file mode 100644
index 0000000..ea5665a
--- /dev/null
+++ b/syzkaller-repros/linux/2a8db7b9aa28c21f3b500e5781edcfd30a70dc4f.c
@@ -0,0 +1,369 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ check_leaks();
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_pipe2, 0x20000100, 0);
+ if (res != -1) {
+ r[0] = *(uint32_t*)0x20000100;
+ r[1] = *(uint32_t*)0x20000104;
+ }
+ memcpy((void*)0x20000300, "./file0\000", 8);
+ syscall(__NR_mkdir, 0x20000300, 0);
+ memcpy((void*)0x20000000, "./file0\000", 8);
+ memcpy((void*)0x20000040, "9p\000", 3);
+ memcpy((void*)0x20000480, "trans=fd,", 9);
+ memcpy((void*)0x20000489, "rfdno", 5);
+ *(uint8_t*)0x2000048e = 0x3d;
+ sprintf((char*)0x2000048f, "0x%016llx", (long long)r[0]);
+ *(uint8_t*)0x200004a1 = 0x2c;
+ memcpy((void*)0x200004a2, "wfdno", 5);
+ *(uint8_t*)0x200004a7 = 0x3d;
+ sprintf((char*)0x200004a8, "0x%016llx", (long long)r[1]);
+ *(uint8_t*)0x200004ba = 0x2c;
+ memcpy((void*)0x200004bb, "cachetag", 8);
+ *(uint8_t*)0x200004c3 = 0x3d;
+ memcpy((void*)0x200004c4, "/(mime_typesecurity", 19);
+ *(uint8_t*)0x200004d7 = 0x2c;
+ memcpy((void*)0x200004d8, "dont_measure", 12);
+ *(uint8_t*)0x200004e4 = 0x2c;
+ memcpy((void*)0x200004e5, "rootcontext", 11);
+ *(uint8_t*)0x200004f0 = 0x3d;
+ memcpy((void*)0x200004f1, "system_u", 8);
+ *(uint8_t*)0x200004f9 = 0x2c;
+ memcpy((void*)0x200004fa, "uid", 3);
+ *(uint8_t*)0x200004fd = 0x3d;
+ sprintf((char*)0x200004fe, "%020llu", (long long)0);
+ *(uint8_t*)0x20000512 = 0x2c;
+ memcpy((void*)0x20000513, "uid>", 4);
+ sprintf((char*)0x20000517, "%020llu", (long long)0);
+ *(uint8_t*)0x2000052b = 0x2c;
+ memcpy((void*)0x2000052c, "context", 7);
+ *(uint8_t*)0x20000533 = 0x3d;
+ memcpy((void*)0x20000534, "root", 4);
+ *(uint8_t*)0x20000538 = 0x2c;
+ memcpy((void*)0x20000539, "fowner<", 7);
+ sprintf((char*)0x20000540, "%020llu", (long long)0);
+ *(uint8_t*)0x20000554 = 0x2c;
+ memcpy((void*)0x20000555, "subj_role", 9);
+ *(uint8_t*)0x2000055e = 0x3d;
+ *(uint8_t*)0x2000055f = 0x2c;
+ *(uint8_t*)0x20000560 = 0;
+ syscall(__NR_mount, 0, 0x20000000, 0x20000040, 0, 0x20000480);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2af2eeb89a213fc15d0c8d7e31f5dc26f885d62c.c b/syzkaller-repros/linux/2af2eeb89a213fc15d0c8d7e31f5dc26f885d62c.c
new file mode 100644
index 0000000..645ff9b
--- /dev/null
+++ b/syzkaller-repros/linux/2af2eeb89a213fc15d0c8d7e31f5dc26f885d62c.c
@@ -0,0 +1,160 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+}
+
+#define SYZ_HAVE_RESET_TEST 1
+static void reset_test()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ reset_test();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ long res = 0;
+ memcpy((void*)0x20000100, "/dev/video#", 12);
+ res = syz_open_dev(0x20000100, 3, 0);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_read, r[0], 0x20000000, 0x62);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2b62c2c92d8097048ae927f455695678667b4d28.c b/syzkaller-repros/linux/2b62c2c92d8097048ae927f455695678667b4d28.c
new file mode 100644
index 0000000..b5cddca
--- /dev/null
+++ b/syzkaller-repros/linux/2b62c2c92d8097048ae927f455695678667b4d28.c
@@ -0,0 +1,754 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000040, "virt_wifi0\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20000050 = 0;
+ syscall(__NR_ioctl, -1, 0x8934ul, 0x20000040ul);
+ syscall(__NR_ioctl, r[0], 0x800000000008b24ul, 0x20000040ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2c02304bfffcd639c6a840b566f6083aed4191e1.c b/syzkaller-repros/linux/2c02304bfffcd639c6a840b566f6083aed4191e1.c
new file mode 100644
index 0000000..3b974b1
--- /dev/null
+++ b/syzkaller-repros/linux/2c02304bfffcd639c6a840b566f6083aed4191e1.c
@@ -0,0 +1,1373 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ exit(1);
+ }
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 11; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_pipe, 0ul);
+ break;
+ case 1:
+ syscall(__NR_ioctl, -1, 0xc028660ful, 0ul);
+ break;
+ case 2:
+ syscall(__NR_write, -1, 0ul, 0ul);
+ break;
+ case 3:
+ NONFAILING(memcpy((void*)0x20000040, "./bus\000", 6));
+ res = syscall(__NR_creat, 0x20000040ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 4:
+ syscall(__NR_fallocate, r[0], 0x10ul, 0x8003ul, 0x8020001ul);
+ break;
+ case 5:
+ NONFAILING(memcpy((void*)0x20000140, "./bus\000", 6));
+ res = syscall(__NR_open, 0x20000140ul, 0x141042ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 6:
+ NONFAILING(memcpy((void*)0x20000300, "./file0\000", 8));
+ res = syscall(__NR_creat, 0x20000300ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 7:
+ NONFAILING(*(uint32_t*)0x20000280 = 0);
+ NONFAILING(*(uint8_t*)0x20000284 = 0x7b);
+ NONFAILING(*(uint16_t*)0x20000285 = 0);
+ syscall(__NR_write, r[2], 0x20000280ul, 0x1033bul);
+ break;
+ case 8:
+ syscall(__NR_fdatasync, r[2]);
+ break;
+ case 9:
+ NONFAILING(*(uint32_t*)0x20000200 = 0);
+ NONFAILING(*(uint32_t*)0x20000204 = r[2]);
+ NONFAILING(*(uint64_t*)0x20000208 = 0x8028);
+ NONFAILING(*(uint64_t*)0x20000210 = 0);
+ NONFAILING(*(uint64_t*)0x20000218 = 0);
+ NONFAILING(*(uint64_t*)0x20000220 = 0);
+ syscall(__NR_ioctl, r[1], 0xc028660ful, 0x20000200ul);
+ break;
+ case 10:
+ NONFAILING(memcpy((void*)0x20000300, "./file0\000", 8));
+ syscall(__NR_creat, 0x20000300ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2ccb2784ac25def3b08e246ef3a10e1b6e4eb3e3.c b/syzkaller-repros/linux/2ccb2784ac25def3b08e246ef3a10e1b6e4eb3e3.c
new file mode 100644
index 0000000..df5638a
--- /dev/null
+++ b/syzkaller-repros/linux/2ccb2784ac25def3b08e246ef3a10e1b6e4eb3e3.c
@@ -0,0 +1,1019 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 21; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+uint64_t r[13] = {0xffffffffffffffff, 0x0, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0x0, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0x0, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0x0, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ memcpy((void*)0x20001840,
+ "vcan0\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20001850 = 0;
+ res = syscall(__NR_ioctl, r[0], 0x8933ul, 0x20001840ul);
+ if (res != -1)
+ r[1] = *(uint32_t*)0x20001850;
+ break;
+ case 2:
+ res = syscall(__NR_socket, 0x1dul, 2ul, 7ul);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 3:
+ res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 4:
+ memcpy((void*)0x20001840,
+ "vcan0\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20001850 = 0;
+ res = syscall(__NR_ioctl, r[3], 0x8933ul, 0x20001840ul);
+ if (res != -1)
+ r[4] = *(uint32_t*)0x20001850;
+ break;
+ case 5:
+ *(uint16_t*)0x20000240 = 0x1d;
+ *(uint32_t*)0x20000244 = r[4];
+ *(uint64_t*)0x20000248 = 0;
+ *(uint8_t*)0x20000250 = 0;
+ *(uint8_t*)0x20000251 = 0;
+ *(uint8_t*)0x20000252 = 0;
+ *(uint8_t*)0x20000253 = 0;
+ *(uint8_t*)0x20000254 = 0;
+ syscall(__NR_bind, r[2], 0x20000240ul, 0x18ul);
+ break;
+ case 6:
+ *(uint16_t*)0x20000180 = 0x1d;
+ *(uint32_t*)0x20000184 = r[1];
+ *(uint64_t*)0x20000188 = 0;
+ *(uint8_t*)0x20000190 = 0;
+ *(uint8_t*)0x20000191 = 1;
+ *(uint8_t*)0x20000192 = 0;
+ *(uint8_t*)0x20000193 = 0;
+ *(uint8_t*)0x20000194 = 0;
+ syscall(__NR_connect, r[2], 0x20000180ul, 0x18ul);
+ break;
+ case 7:
+ res = syscall(__NR_dup, r[2]);
+ if (res != -1)
+ r[5] = res;
+ break;
+ case 8:
+ res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+ if (res != -1)
+ r[6] = res;
+ break;
+ case 9:
+ memcpy((void*)0x20001840,
+ "vcan0\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20001850 = 0;
+ res = syscall(__NR_ioctl, r[6], 0x8933ul, 0x20001840ul);
+ if (res != -1)
+ r[7] = *(uint32_t*)0x20001850;
+ break;
+ case 10:
+ res = syscall(__NR_socket, 0x1dul, 2ul, 7ul);
+ if (res != -1)
+ r[8] = res;
+ break;
+ case 11:
+ res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+ if (res != -1)
+ r[9] = res;
+ break;
+ case 12:
+ memcpy((void*)0x20001840,
+ "vcan0\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20001850 = 0;
+ res = syscall(__NR_ioctl, r[9], 0x8933ul, 0x20001840ul);
+ if (res != -1)
+ r[10] = *(uint32_t*)0x20001850;
+ break;
+ case 13:
+ *(uint16_t*)0x20000240 = 0x1d;
+ *(uint32_t*)0x20000244 = r[10];
+ *(uint64_t*)0x20000248 = 0;
+ *(uint8_t*)0x20000250 = 0;
+ *(uint8_t*)0x20000251 = 0;
+ *(uint8_t*)0x20000252 = 0;
+ *(uint8_t*)0x20000253 = 0;
+ *(uint8_t*)0x20000254 = 0;
+ syscall(__NR_bind, r[8], 0x20000240ul, 0x18ul);
+ break;
+ case 14:
+ *(uint16_t*)0x20000180 = 0x1d;
+ *(uint32_t*)0x20000184 = r[7];
+ *(uint64_t*)0x20000188 = 0;
+ *(uint8_t*)0x20000190 = 0;
+ *(uint8_t*)0x20000191 = 0;
+ *(uint8_t*)0x20000192 = 0;
+ *(uint8_t*)0x20000193 = 0;
+ *(uint8_t*)0x20000194 = 0;
+ syscall(__NR_connect, r[8], 0x20000180ul, 0x18ul);
+ break;
+ case 15:
+ res = syscall(__NR_dup, r[8]);
+ if (res != -1)
+ r[11] = res;
+ break;
+ case 16:
+ memcpy((void*)0x200008c0, "./file0\000", 8);
+ res = syscall(__NR_open, 0x200008c0ul, 0x20141042ul, 0ul);
+ if (res != -1)
+ r[12] = res;
+ break;
+ case 17:
+ syscall(__NR_ftruncate, r[12], 0x80080ul);
+ break;
+ case 18:
+ syscall(__NR_sendfile, r[11], r[12], 0ul, 0x200800100000001ul);
+ break;
+ case 19:
+ *(uint8_t*)0x20000040 = 0x62;
+ *(uint8_t*)0x20000041 = 5;
+ *(uint8_t*)0x20000042 = 0x2c;
+ *(uint8_t*)0x20000043 = 1;
+ *(uint32_t*)0x20000048 = 0x92;
+ *(uint8_t*)0x20000058 = 5;
+ *(uint8_t*)0x20000059 = 0x40;
+ *(uint8_t*)0x2000005a = 6;
+ *(uint8_t*)0x2000005b = 6;
+ *(uint32_t*)0x20000060 = 2;
+ *(uint32_t*)0x20000064 = 4;
+ *(uint32_t*)0x20000068 = 5;
+ *(uint8_t*)0x20000070 = 1;
+ *(uint8_t*)0x20000071 = 8;
+ *(uint8_t*)0x20000072 = 7;
+ *(uint8_t*)0x20000073 = 8;
+ *(uint32_t*)0x20000078 = 0xffff;
+ *(uint8_t*)0x20000088 = 0x7f;
+ *(uint8_t*)0x20000089 = 5;
+ *(uint8_t*)0x2000008a = 0x20;
+ *(uint8_t*)0x2000008b = 0x80;
+ *(uint8_t*)0x20000090 = 0x80;
+ *(uint8_t*)0x20000091 = 1;
+ *(uint8_t*)0x20000092 = 5;
+ *(uint8_t*)0x20000093 = 6;
+ *(uint32_t*)0x20000094 = 2;
+ *(uint8_t*)0x200000a0 = 0x22;
+ *(uint8_t*)0x200000a1 = 0x81;
+ *(uint8_t*)0x200000a2 = 1;
+ *(uint8_t*)0x200000a3 = -1;
+ *(uint32_t*)0x200000a8 = 0x200;
+ *(uint8_t*)0x200000b8 = 0;
+ *(uint8_t*)0x200000b9 = 0x3f;
+ *(uint8_t*)0x200000ba = 2;
+ *(uint8_t*)0x200000bb = 0x3f;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint64_t*)0x200000c4 = 0;
+ *(uint8_t*)0x200000d0 = 0;
+ *(uint8_t*)0x200000d1 = 7;
+ *(uint8_t*)0x200000d2 = 0x80;
+ *(uint8_t*)0x200000d3 = 0xaa;
+ *(uint32_t*)0x200000d8 = 0x20;
+ *(uint8_t*)0x200000e8 = 0x20;
+ *(uint8_t*)0x200000e9 = 0x5a;
+ *(uint8_t*)0x200000ea = 0x80;
+ *(uint8_t*)0x200000eb = 0;
+ *(uint32_t*)0x200000f0 = 0;
+ *(uint64_t*)0x200000f4 = 0;
+ *(uint8_t*)0x20000100 = 0x81;
+ *(uint8_t*)0x20000101 = 0x4b;
+ *(uint8_t*)0x20000102 = 2;
+ *(uint8_t*)0x20000103 = -1;
+ *(uint32_t*)0x20000108 = 8;
+ *(uint8_t*)0x20000118 = 2;
+ *(uint8_t*)0x20000119 = 9;
+ *(uint8_t*)0x2000011a = 0xfc;
+ *(uint8_t*)0x2000011b = 5;
+ *(uint8_t*)0x20000120 = 0;
+ *(uint32_t*)0x20000124 = 0x1000;
+ *(uint32_t*)0x20000128 = 8;
+ syscall(__NR_write, r[5], 0x20000040ul, 0xf0ul);
+ break;
+ case 20:
+ syscall(__NR_ioctl, -1, 0x5429ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2d3cae8f6da6f9748ccaece51c90ef808dc02c1e.c b/syzkaller-repros/linux/2d3cae8f6da6f9748ccaece51c90ef808dc02c1e.c
new file mode 100644
index 0000000..e63a233
--- /dev/null
+++ b/syzkaller-repros/linux/2d3cae8f6da6f9748ccaece51c90ef808dc02c1e.c
@@ -0,0 +1,344 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000400;
+ memcpy((void*)0x20000400,
+ "\x54\x00\x00\x00\x30\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x40\x00\x01\x00\x3c\x00\x01\x00\x08\x00\x01\x00"
+ "\x69\x66\x65\x00\x2c\x00\x02\x80\x1c\x00\x01\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x0c\x00\x06\x00\x04\x00\x01\x00\x04\x00\x04\x00"
+ "\x04\x00\x06\x00\x18\x68\x2c\x99\x4a\xa0\x29\x37\xd9\x71\x9b\x26"
+ "\x10\x9f\x55\x75\x5d\x96\x4e\xd1\x53\x86\xea\xc6\xac\x81\xda\x3a"
+ "\x7b\x07\x5c\x62\x82\x4d\x14\xd2\xbf\x1d\x4e\x85\x7d\xeb\x41\x68"
+ "\xe8\x76\x55\x2c\x9b\xdd\x96\xd0\x81\xbd\xc3\x7c\x65\xf9\x52\xa7"
+ "\xf1\x7a\xac\xc3\x9b\x7c\xa7\x78\x0b\xb1\x2b\xcb\x0c\xc6\x13\xfd"
+ "\x42\x1c\xcd\x67\x76\xdd\x44\x1d\x4c\x72\x74\x2b\x8c\x52\x7b\xf7"
+ "\x30\xc9\x86\x0a\x41\x3a\xf5\x99\x26\x5e\x9e\x7d\x18\x65\x99\x25"
+ "\x1d\xc5\x48\x1a\xac\x8c\x89\x3b\x19\xd7\xbc\xb6\xce\x57\x94\xac"
+ "\x26\xef\xe5\xfe\xee\xba\x2d\x95\xd9\x00\x82\xd1\x8d\xd3\x29\x50"
+ "\x8b\xeb\x59\xa7\xed\xc0\x7e\x47\xec\x8c\x83\xa6\xd6\x38\xf8\x8e",
+ 240);
+ *(uint64_t*)0x200002c8 = 0x54;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000300ul, 0ul);
+ break;
+ case 3:
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x24;
+ *(uint16_t*)0x20000004 = 0x31;
+ *(uint16_t*)0x20000006 = 0x101;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 0;
+ *(uint16_t*)0x20000012 = 0;
+ *(uint16_t*)0x20000014 = 0x10;
+ *(uint16_t*)0x20000016 = 1;
+ *(uint16_t*)0x20000018 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000001a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000001b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000001b, 0, 7, 1);
+ *(uint16_t*)0x2000001c = 8;
+ *(uint16_t*)0x2000001e = 1;
+ memcpy((void*)0x20000020, "ife\000", 4);
+ *(uint64_t*)0x200002c8 = 0x24;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2d970fcf71d6825019b2cb7dd665f4cb4e900ca6.c b/syzkaller-repros/linux/2d970fcf71d6825019b2cb7dd665f4cb4e900ca6.c
new file mode 100644
index 0000000..a683c2d
--- /dev/null
+++ b/syzkaller-repros/linux/2d970fcf71d6825019b2cb7dd665f4cb4e900ca6.c
@@ -0,0 +1,269 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_recvmsg, -1, 0ul, 0x10000ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0x44ul);
+ memcpy((void*)0x200026c0, "/sys/kernel/debug/bluetooth/6lowpan_enable\000",
+ 43);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200026c0ul, 2ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20002700, "1", 1);
+ syscall(__NR_write, r[0], 0x20002700ul, 1ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 6; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2ef9a3fd765fc87a95d0b4a915eb748136d87485.c b/syzkaller-repros/linux/2ef9a3fd765fc87a95d0b4a915eb748136d87485.c
new file mode 100644
index 0000000..f3e81b2
--- /dev/null
+++ b/syzkaller-repros/linux/2ef9a3fd765fc87a95d0b4a915eb748136d87485.c
@@ -0,0 +1,431 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 3; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000040, "/dev/watch_queue\000", 17);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_ioctl, r[0], 0x5760ul, 8ul);
+ break;
+ case 2:
+ *(uint32_t*)0x20000000 = r[0];
+ *(uint16_t*)0x20000004 = 0;
+ *(uint16_t*)0x20000006 = 0;
+ syscall(__NR_ppoll, 0x20000000ul, 0xf7ul, 0ul, 0ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2f1a54e3b103141be11150b4dc1d6ee81774a8d5.c b/syzkaller-repros/linux/2f1a54e3b103141be11150b4dc1d6ee81774a8d5.c
new file mode 100644
index 0000000..27e2494
--- /dev/null
+++ b/syzkaller-repros/linux/2f1a54e3b103141be11150b4dc1d6ee81774a8d5.c
@@ -0,0 +1,156 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/vhci\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000000, 0x246, 0);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x200000c0, "\xff\x80", 2);
+ syscall(__NR_write, r[0], 0x200000c0, 2);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/2fdd0aa0525cd6170e6b470d3f4beebcc3c2e063.c b/syzkaller-repros/linux/2fdd0aa0525cd6170e6b470d3f4beebcc3c2e063.c
new file mode 100644
index 0000000..6305bfe
--- /dev/null
+++ b/syzkaller-repros/linux/2fdd0aa0525cd6170e6b470d3f4beebcc3c2e063.c
@@ -0,0 +1,280 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x200000c0, "/dev/ppp\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200000c0ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0xc004743eul, 0x20000100ul);
+ *(uint32_t*)0x20000000 = 1;
+ *(uint64_t*)0x20000008 = 0x20000240;
+ syscall(__NR_ioctl, -1, 0x800448d2ul, 0x20000000ul);
+ syscall(__NR_ioctl, r[0], 0x40107447ul, 0x20000000ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/315c108e5692fe6f8a6228e0538dba71bf92583f.c b/syzkaller-repros/linux/315c108e5692fe6f8a6228e0538dba71bf92583f.c
new file mode 100644
index 0000000..4c8be2f
--- /dev/null
+++ b/syzkaller-repros/linux/315c108e5692fe6f8a6228e0538dba71bf92583f.c
@@ -0,0 +1,289 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000140, "/dev/watch_queue\000", 17);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000140ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000240 = 1;
+ *(uint32_t*)0x20000244 = 0;
+ *(uint32_t*)0x20000248 = 0x300;
+ *(uint32_t*)0x2000024c = 0;
+ *(uint32_t*)0x20000250 = 0;
+ *(uint32_t*)0x20000254 = 0;
+ *(uint32_t*)0x20000258 = 0;
+ *(uint32_t*)0x2000025c = 0;
+ *(uint32_t*)0x20000260 = 0;
+ *(uint32_t*)0x20000264 = 0;
+ *(uint32_t*)0x20000268 = 0;
+ *(uint32_t*)0x2000026c = 0;
+ *(uint32_t*)0x20000270 = 0;
+ syscall(__NR_ioctl, r[0], 0x5761ul, 0x20000240ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/317ef02b0d5cbd19d445294fed91453c7f970fc3.c b/syzkaller-repros/linux/317ef02b0d5cbd19d445294fed91453c7f970fc3.c
new file mode 100644
index 0000000..8cdfbd9
--- /dev/null
+++ b/syzkaller-repros/linux/317ef02b0d5cbd19d445294fed91453c7f970fc3.c
@@ -0,0 +1,299 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0xaul, 0x80000000000001ul, 0x84ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20444ff8 = 0;
+ *(uint32_t*)0x20444ffc = 7;
+ syscall(__NR_setsockopt, r[0], 0x84ul, 0x76ul, 0x20444ff8ul, 8ul);
+ *(uint16_t*)0x20cf6fe4 = 0xa;
+ *(uint16_t*)0x20cf6fe6 = htobe16(0x4e23);
+ *(uint32_t*)0x20cf6fe8 = htobe32(0);
+ *(uint64_t*)0x20cf6fec = htobe64(0);
+ *(uint64_t*)0x20cf6ff4 = htobe64(1);
+ *(uint32_t*)0x20cf6ffc = 0;
+ syscall(__NR_setsockopt, r[0], 0x84ul, 0x64ul, 0x20cf6fe4ul, 0x1cul);
+ *(uint32_t*)0x20107ff8 = 0;
+ *(uint32_t*)0x20107ffc = 0x10040000;
+ syscall(__NR_setsockopt, r[0], 0x84ul, 0x75ul, 0x20107ff8ul, 8ul);
+ *(uint16_t*)0x208c0000 = 0xa;
+ *(uint16_t*)0x208c0002 = htobe16(0x4e23);
+ *(uint32_t*)0x208c0004 = htobe32(0);
+ *(uint64_t*)0x208c0008 = htobe64(0);
+ *(uint64_t*)0x208c0010 = htobe64(1);
+ *(uint32_t*)0x208c0018 = 0;
+ syscall(__NR_connect, r[0], 0x208c0000ul, 0x1cul);
+ *(uint32_t*)0x2081e000 = 0;
+ *(uint16_t*)0x2081e004 = 0x3b;
+ *(uint16_t*)0x2081e006 = 0x29;
+ *(uint16_t*)0x2081e008 = 0;
+ syscall(__NR_setsockopt, r[0], 0x84ul, 0x77ul, 0x2081e000ul, 0x2deul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/322adf827c43760c788a245ff0e49c8dffd9de9e.c b/syzkaller-repros/linux/322adf827c43760c788a245ff0e49c8dffd9de9e.c
new file mode 100644
index 0000000..1858588
--- /dev/null
+++ b/syzkaller-repros/linux/322adf827c43760c788a245ff0e49c8dffd9de9e.c
@@ -0,0 +1,280 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#ifndef __NR_watch_devices
+#define __NR_watch_devices 436
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/watch_queue\000", 17);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_watch_devices, r[0], 0x42ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3452dae8974e3ffaa70ac20870ffda7a786abc12.c b/syzkaller-repros/linux/3452dae8974e3ffaa70ac20870ffda7a786abc12.c
new file mode 100644
index 0000000..3b2772e
--- /dev/null
+++ b/syzkaller-repros/linux/3452dae8974e3ffaa70ac20870ffda7a786abc12.c
@@ -0,0 +1,226 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 6; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000000, "/dev/loop#\000", 11);
+ res = syz_open_dev(0x20000000, 6, 0x40);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ memcpy((void*)0x20000080, "/dev/nullb0\000", 12);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000080ul,
+ 0x4000000004002ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ syscall(__NR_ioctl, r[0], 0x4c00ul, r[1]);
+ break;
+ case 3:
+ memcpy((void*)0x20000080, "/dev/nullb0\000", 12);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000080ul,
+ 0x4000000004002ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 4:
+ syscall(__NR_mmap, 0x20000000ul, 0xe7e000ul, 0x200000eul, 0x13ul, r[2], 0);
+ break;
+ case 5:
+ syscall(__NR_ioctl, -1, 0x4606ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/35e19667650e0565c7f9d20e8e9306f919f5ea09.c b/syzkaller-repros/linux/35e19667650e0565c7f9d20e8e9306f919f5ea09.c
new file mode 100644
index 0000000..eb2ca85
--- /dev/null
+++ b/syzkaller-repros/linux/35e19667650e0565c7f9d20e8e9306f919f5ea09.c
@@ -0,0 +1,331 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x200002c0, "/dev/fd#\000", 9);
+ res = syz_open_dev(0x200002c0, 0x691, 2);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000300 = 2;
+ *(uint64_t*)0x20000308 = 0x200000c0;
+ memcpy((void*)0x200000c0, "\x94\xc4\xf9", 3);
+ *(uint64_t*)0x20000310 = 0;
+ *(uint64_t*)0x20000318 = 0;
+ *(uint64_t*)0x20000320 = 0x1000002b3;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ *(uint8_t*)0x20000334 = 0;
+ *(uint8_t*)0x20000335 = 2;
+ memcpy((void*)0x20000336,
+ "\xda\xf7\x04\x68\xe3\x30\x40\x45\x36\xc2\xa3\xc0\xa1\xfd\x7d\x37",
+ 16);
+ *(uint8_t*)0x20000346 = 0;
+ *(uint8_t*)0x20000347 = 0;
+ *(uint8_t*)0x20000348 = 0;
+ *(uint8_t*)0x20000349 = 0;
+ *(uint8_t*)0x2000034a = 0;
+ *(uint8_t*)0x2000034b = 0;
+ *(uint8_t*)0x2000034c = 0;
+ *(uint8_t*)0x2000034d = 0;
+ *(uint8_t*)0x2000034e = 0;
+ *(uint8_t*)0x2000034f = 0;
+ *(uint8_t*)0x20000350 = 0;
+ *(uint8_t*)0x20000351 = 0;
+ *(uint8_t*)0x20000352 = 0;
+ *(uint8_t*)0x20000353 = 0;
+ *(uint8_t*)0x20000354 = 0;
+ *(uint8_t*)0x20000355 = 0;
+ *(uint8_t*)0x20000356 = 0;
+ *(uint32_t*)0x20000358 = 0;
+ *(uint32_t*)0x2000035c = 0;
+ *(uint32_t*)0x20000360 = 0;
+ *(uint32_t*)0x20000364 = 0;
+ syscall(__NR_ioctl, r[0], 0x258ul, 0x20000300ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3652334fad941714f23fe6bac16b2020baf36296.c b/syzkaller-repros/linux/3652334fad941714f23fe6bac16b2020baf36296.c
new file mode 100644
index 0000000..d21d0f7
--- /dev/null
+++ b/syzkaller-repros/linux/3652334fad941714f23fe6bac16b2020baf36296.c
@@ -0,0 +1,589 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000140, "/dev/infiniband/rdma_cm\000", 24);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000140ul, 2ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ memcpy((void*)0x20000140, "/dev/infiniband/rdma_cm\000", 24);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000140ul, 2ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ *(uint32_t*)0x20000280 = 0;
+ *(uint16_t*)0x20000284 = 0x18;
+ *(uint16_t*)0x20000286 = 0xfa00;
+ *(uint64_t*)0x20000288 = 3;
+ *(uint64_t*)0x20000290 = 0x20000000;
+ *(uint16_t*)0x20000298 = 2;
+ *(uint8_t*)0x2000029a = 0;
+ *(uint8_t*)0x2000029b = 0;
+ *(uint8_t*)0x2000029c = 0;
+ *(uint8_t*)0x2000029d = 0;
+ *(uint8_t*)0x2000029e = 0;
+ *(uint8_t*)0x2000029f = 0;
+ res = syscall(__NR_write, r[1], 0x20000280ul, 0x20ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000000;
+ break;
+ case 3:
+ *(uint32_t*)0x20000400 = 3;
+ *(uint16_t*)0x20000404 = 0x40;
+ *(uint16_t*)0x20000406 = 0xfa00;
+ *(uint16_t*)0x20000408 = 0xa;
+ *(uint16_t*)0x2000040a = htobe16(0x4e20);
+ *(uint32_t*)0x2000040c = htobe32(0);
+ *(uint64_t*)0x20000410 = htobe64(0);
+ *(uint64_t*)0x20000418 = htobe64(1);
+ *(uint32_t*)0x20000420 = 0;
+ *(uint16_t*)0x20000424 = 0xa;
+ *(uint16_t*)0x20000426 = htobe16(0);
+ *(uint32_t*)0x20000428 = htobe32(0);
+ *(uint8_t*)0x2000042c = 0xfe;
+ *(uint8_t*)0x2000042d = 0x80;
+ *(uint8_t*)0x2000042e = 0;
+ *(uint8_t*)0x2000042f = 0;
+ *(uint8_t*)0x20000430 = 0;
+ *(uint8_t*)0x20000431 = 0;
+ *(uint8_t*)0x20000432 = 0;
+ *(uint8_t*)0x20000433 = 0;
+ *(uint8_t*)0x20000434 = 0;
+ *(uint8_t*)0x20000435 = 0;
+ *(uint8_t*)0x20000436 = 0;
+ *(uint8_t*)0x20000437 = 0;
+ *(uint8_t*)0x20000438 = 0;
+ *(uint8_t*)0x20000439 = 0;
+ *(uint8_t*)0x2000043a = 0;
+ *(uint8_t*)0x2000043b = 0xbb;
+ *(uint32_t*)0x2000043c = 6;
+ *(uint32_t*)0x20000440 = r[2];
+ *(uint32_t*)0x20000444 = 0;
+ syscall(__NR_write, r[1], 0x20000400ul, 0x48ul);
+ break;
+ case 4:
+ *(uint32_t*)0x20000100 = 0x12;
+ *(uint16_t*)0x20000104 = 0x10;
+ *(uint16_t*)0x20000106 = 0xfa00;
+ *(uint64_t*)0x20000108 = 0;
+ *(uint32_t*)0x20000110 = r[2];
+ *(uint32_t*)0x20000114 = r[1];
+ syscall(__NR_write, r[0], 0x20000100ul, 0x18ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3742e99590e09f89d6f92929fafc9cdad91139f4.c b/syzkaller-repros/linux/3742e99590e09f89d6f92929fafc9cdad91139f4.c
new file mode 100644
index 0000000..441d384
--- /dev/null
+++ b/syzkaller-repros/linux/3742e99590e09f89d6f92929fafc9cdad91139f4.c
@@ -0,0 +1,294 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x200000c0, "/dev/ttyS3\000", 11);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200000c0ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000240 = 0x10;
+ *(uint32_t*)0x20000244 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint32_t*)0x2000024c = 0;
+ *(uint32_t*)0x20000250 = 0;
+ *(uint32_t*)0x20000254 = 0;
+ *(uint32_t*)0x20000258 = 0;
+ *(uint32_t*)0x2000025c = 0x7fffffff;
+ *(uint32_t*)0x20000260 = 0xf4070000;
+ *(uint8_t*)0x20000264 = 0;
+ *(uint8_t*)0x20000265 = 0;
+ *(uint32_t*)0x20000268 = 0;
+ *(uint16_t*)0x2000026c = 0;
+ *(uint16_t*)0x2000026e = 0;
+ *(uint64_t*)0x20000270 = 0;
+ *(uint16_t*)0x20000278 = 0;
+ *(uint32_t*)0x2000027c = 0;
+ *(uint64_t*)0x20000280 = 0;
+ syscall(__NR_ioctl, r[0], 0x541ful, 0x20000240ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/38274ed551786328c3f7cc4ea683ac544e58696f.c b/syzkaller-repros/linux/38274ed551786328c3f7cc4ea683ac544e58696f.c
new file mode 100644
index 0000000..4a72c9d
--- /dev/null
+++ b/syzkaller-repros/linux/38274ed551786328c3f7cc4ea683ac544e58696f.c
@@ -0,0 +1,655 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000000, "/dev/dsp\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint64_t*)0x20000240 = 6;
+ syscall(__NR_ioctl, r[0], 0x800000c004500aul, 0x20000240ul);
+ break;
+ case 2:
+ *(uint64_t*)0x200000c0 = 0;
+ syscall(__NR_ioctl, r[0], 0x800000c0045002ul, 0x200000c0ul);
+ break;
+ case 3:
+ syscall(__NR_read, r[0], 0x20000380ul, 0x1000ul);
+ break;
+ case 4:
+ syscall(__NR_ioctl, r[0], 0x5000ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/392a25327e23d5fb6eacf4092fced4405ca198cc.c b/syzkaller-repros/linux/392a25327e23d5fb6eacf4092fced4405ca198cc.c
new file mode 100644
index 0000000..bd2d5c5
--- /dev/null
+++ b/syzkaller-repros/linux/392a25327e23d5fb6eacf4092fced4405ca198cc.c
@@ -0,0 +1,65 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+long r[27];
+void loop()
+{
+ memset(r, -1, sizeof(r));
+ r[0] = syscall(__NR_mmap, 0x20000000ul, 0xfff000ul, 0x3ul, 0x32ul,
+ 0xfffffffffffffffful, 0x0ul);
+ r[1] = syscall(__NR_socket, 0xaul, 0x1ul, 0x8010000000000084ul);
+ memcpy((void*)0x2040a000,
+ "\x17\x32\xfb\xd6\x77\x6e\x71\xf4\x93\x32\x14\x53\x6e\x52\x59"
+ "\x42\x9c\x7d\xed\xa7\xdc\x30\x27\x16\xd7\xec\x0c\x11\x6a\x76"
+ "\x05\xbe\x6a\x78\x21\x91\xc1\xe9\x53\xa0\xaf\x13\x7a\x8e\x59"
+ "\x66\xb7\x1d\xda\xa7\x38\x01\x19\xbe\x69\x50\x2c\x3d\x30\x7b"
+ "\x90\x7c\x2f\x6d\x5f\xea\x7b\x85\xc7\x82\x25\x20\x2d\xfd\x69"
+ "\xa8\x38\x9b\xf0\x7d\xcd\x69\x44\x90\xec\xf5\x06\x51\x96\xab"
+ "\xea\x2e\xb0\xba\x5a\x75\x41\xcf\xfd\x80\x31\x8a\x4c\x28\xa4"
+ "\x26\x4c\x06\x96\x39\x77\x1b\x26\x3f\xa1\x01\x47\x31\x57\x83"
+ "\x66\xd4\xc2\xde\x62\x4d\xd6\x2d\x1f\x39\xd4\x31\x4c\x4a\x03"
+ "\xa4\xcc\x64\x4a\xf8\x37\xa8\xdd\xc1\x75\x1f\xe2\x2c\xdc\x41"
+ "\xcc\xde\xdd\x76\xdc\x92\x30\xc6\xf5\xae\x12\xc9\x31\x6c\x39"
+ "\x9b\x61\x80\x4c\xdb\x61\x93\x75\x49\xb9\x80\x85\xda\x63\xcc"
+ "\x7b\x5e\x01\xed\xb7\xea\x5d\xfc\xd3\x29\xee\xf0\x38\xe9\x9b"
+ "\xbb\x78\x27\xfd\x26\xfa\x19\x69\x14\x35\x6f\x7b\xd6\x9d\xd2"
+ "\xb6\xfe\x12\x5a\x0e\x2a\xcd\x70\xa5",
+ 219);
+ *(uint16_t*)0x20132000 = (uint16_t)0xa;
+ *(uint16_t*)0x20132002 = (uint16_t)0x214e;
+ *(uint32_t*)0x20132004 = (uint32_t)0xb044;
+ *(uint8_t*)0x20132008 = (uint8_t)0xfe;
+ *(uint8_t*)0x20132009 = (uint8_t)0x80;
+ *(uint8_t*)0x2013200a = (uint8_t)0x0;
+ *(uint8_t*)0x2013200b = (uint8_t)0x0;
+ *(uint8_t*)0x2013200c = (uint8_t)0x0;
+ *(uint8_t*)0x2013200d = (uint8_t)0x0;
+ *(uint8_t*)0x2013200e = (uint8_t)0x0;
+ *(uint8_t*)0x2013200f = (uint8_t)0x0;
+ *(uint8_t*)0x20132010 = (uint8_t)0x0;
+ *(uint8_t*)0x20132011 = (uint8_t)0x0;
+ *(uint8_t*)0x20132012 = (uint8_t)0x0;
+ *(uint8_t*)0x20132013 = (uint8_t)0x0;
+ *(uint8_t*)0x20132014 = (uint8_t)0x0;
+ *(uint8_t*)0x20132015 = (uint8_t)0x0;
+ *(uint8_t*)0x20132016 = (uint8_t)0x0;
+ *(uint8_t*)0x20132017 = (uint8_t)0xbb;
+ *(uint32_t*)0x20132018 = (uint32_t)0x1;
+ r[23] = syscall(__NR_sendto, r[1], 0x2040a000ul, 0xdbul, 0x4040ul,
+ 0x20132000ul, 0x1cul);
+ r[24] = syscall(__NR_listen, r[1], 0x2ul);
+ *(uint32_t*)0x207ccffc = (uint32_t)0x1c;
+ r[26] = syscall(__NR_accept, r[1], 0x209ab000ul, 0x207ccffcul);
+}
+
+int main()
+{
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3abf33c7e6568401c02c9e3a0abad08faf29c273.c b/syzkaller-repros/linux/3abf33c7e6568401c02c9e3a0abad08faf29c273.c
new file mode 100644
index 0000000..a8f0ed0
--- /dev/null
+++ b/syzkaller-repros/linux/3abf33c7e6568401c02c9e3a0abad08faf29c273.c
@@ -0,0 +1,781 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000900,
+ "filter\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000",
+ 32);
+ *(uint32_t*)0x20000920 = 4;
+ *(uint32_t*)0x20000924 = 4;
+ *(uint32_t*)0x20000928 = 0x3b8;
+ *(uint32_t*)0x2000092c = 0;
+ *(uint32_t*)0x20000930 = 0;
+ *(uint32_t*)0x20000934 = 0x1d0;
+ *(uint32_t*)0x20000938 = 0x2d0;
+ *(uint32_t*)0x2000093c = 0x2d0;
+ *(uint32_t*)0x20000940 = 0x2d0;
+ *(uint32_t*)0x20000944 = 4;
+ *(uint64_t*)0x20000948 = 0;
+ *(uint8_t*)0x20000950 = 0;
+ *(uint8_t*)0x20000951 = 0;
+ *(uint8_t*)0x20000952 = 0;
+ *(uint8_t*)0x20000953 = 0;
+ *(uint8_t*)0x20000954 = 0;
+ *(uint8_t*)0x20000955 = 0;
+ *(uint8_t*)0x20000956 = 0;
+ *(uint8_t*)0x20000957 = 0;
+ *(uint8_t*)0x20000958 = 0;
+ *(uint8_t*)0x20000959 = 0;
+ *(uint8_t*)0x2000095a = 0;
+ *(uint8_t*)0x2000095b = 0;
+ *(uint8_t*)0x2000095c = 0;
+ *(uint8_t*)0x2000095d = 0;
+ *(uint8_t*)0x2000095e = 0;
+ *(uint8_t*)0x2000095f = 0;
+ *(uint8_t*)0x20000960 = 0;
+ *(uint8_t*)0x20000961 = 0;
+ *(uint8_t*)0x20000962 = 0;
+ *(uint8_t*)0x20000963 = 0;
+ *(uint8_t*)0x20000964 = 0;
+ *(uint8_t*)0x20000965 = 0;
+ *(uint8_t*)0x20000966 = 0;
+ *(uint8_t*)0x20000967 = 0;
+ *(uint8_t*)0x20000968 = 0;
+ *(uint8_t*)0x20000969 = 0;
+ *(uint8_t*)0x2000096a = 0;
+ *(uint8_t*)0x2000096b = 0;
+ *(uint8_t*)0x2000096c = 0;
+ *(uint8_t*)0x2000096d = 0;
+ *(uint8_t*)0x2000096e = 0;
+ *(uint8_t*)0x2000096f = 0;
+ *(uint8_t*)0x20000970 = 0;
+ *(uint8_t*)0x20000971 = 0;
+ *(uint8_t*)0x20000972 = 0;
+ *(uint8_t*)0x20000973 = 0;
+ *(uint8_t*)0x20000974 = 0;
+ *(uint8_t*)0x20000975 = 0;
+ *(uint8_t*)0x20000976 = 0;
+ *(uint8_t*)0x20000977 = 0;
+ *(uint8_t*)0x20000978 = 0;
+ *(uint8_t*)0x20000979 = 0;
+ *(uint8_t*)0x2000097a = 0;
+ *(uint8_t*)0x2000097b = 0;
+ *(uint8_t*)0x2000097c = 0;
+ *(uint8_t*)0x2000097d = 0;
+ *(uint8_t*)0x2000097e = 0;
+ *(uint8_t*)0x2000097f = 0;
+ *(uint8_t*)0x20000980 = 0;
+ *(uint8_t*)0x20000981 = 0;
+ *(uint8_t*)0x20000982 = 0;
+ *(uint8_t*)0x20000983 = 0;
+ *(uint8_t*)0x20000984 = 0;
+ *(uint8_t*)0x20000985 = 0;
+ *(uint8_t*)0x20000986 = 0;
+ *(uint8_t*)0x20000987 = 0;
+ *(uint8_t*)0x20000988 = 0;
+ *(uint8_t*)0x20000989 = 0;
+ *(uint8_t*)0x2000098a = 0;
+ *(uint8_t*)0x2000098b = 0;
+ *(uint8_t*)0x2000098c = 0;
+ *(uint8_t*)0x2000098d = 0;
+ *(uint8_t*)0x2000098e = 0;
+ *(uint8_t*)0x2000098f = 0;
+ *(uint8_t*)0x20000990 = 0;
+ *(uint8_t*)0x20000991 = 0;
+ *(uint8_t*)0x20000992 = 0;
+ *(uint8_t*)0x20000993 = 0;
+ *(uint8_t*)0x20000994 = 0;
+ *(uint8_t*)0x20000995 = 0;
+ *(uint8_t*)0x20000996 = 0;
+ *(uint8_t*)0x20000997 = 0;
+ *(uint8_t*)0x20000998 = 0;
+ *(uint8_t*)0x20000999 = 0;
+ *(uint8_t*)0x2000099a = 0;
+ *(uint8_t*)0x2000099b = 0;
+ *(uint8_t*)0x2000099c = 0;
+ *(uint8_t*)0x2000099d = 0;
+ *(uint8_t*)0x2000099e = 0;
+ *(uint8_t*)0x2000099f = 0;
+ *(uint8_t*)0x200009a0 = 0;
+ *(uint8_t*)0x200009a1 = 0;
+ *(uint8_t*)0x200009a2 = 0;
+ *(uint8_t*)0x200009a3 = 0;
+ *(uint8_t*)0x200009a4 = 0;
+ *(uint8_t*)0x200009a5 = 0;
+ *(uint8_t*)0x200009a6 = 0;
+ *(uint8_t*)0x200009a7 = 0;
+ *(uint8_t*)0x200009a8 = 0;
+ *(uint8_t*)0x200009a9 = 0;
+ *(uint8_t*)0x200009aa = 0;
+ *(uint8_t*)0x200009ab = 0;
+ *(uint8_t*)0x200009ac = 0;
+ *(uint8_t*)0x200009ad = 0;
+ *(uint8_t*)0x200009ae = 0;
+ *(uint8_t*)0x200009af = 0;
+ *(uint8_t*)0x200009b0 = 0;
+ *(uint8_t*)0x200009b1 = 0;
+ *(uint8_t*)0x200009b2 = 0;
+ *(uint8_t*)0x200009b3 = 0;
+ *(uint8_t*)0x200009b4 = 0;
+ *(uint8_t*)0x200009b5 = 0;
+ *(uint8_t*)0x200009b6 = 0;
+ *(uint8_t*)0x200009b7 = 0;
+ *(uint8_t*)0x200009b8 = 0;
+ *(uint8_t*)0x200009b9 = 0;
+ *(uint8_t*)0x200009ba = 0;
+ *(uint8_t*)0x200009bb = 0;
+ *(uint8_t*)0x200009bc = 0;
+ *(uint8_t*)0x200009bd = 0;
+ *(uint8_t*)0x200009be = 0;
+ *(uint8_t*)0x200009bf = 0;
+ *(uint8_t*)0x200009c0 = 0;
+ *(uint8_t*)0x200009c1 = 0;
+ *(uint8_t*)0x200009c2 = 0;
+ *(uint8_t*)0x200009c3 = 0;
+ *(uint8_t*)0x200009c4 = 0;
+ *(uint8_t*)0x200009c5 = 0;
+ *(uint8_t*)0x200009c6 = 0;
+ *(uint8_t*)0x200009c7 = 0;
+ *(uint8_t*)0x200009c8 = 0;
+ *(uint8_t*)0x200009c9 = 0;
+ *(uint8_t*)0x200009ca = 0;
+ *(uint8_t*)0x200009cb = 0;
+ *(uint8_t*)0x200009cc = 0;
+ *(uint8_t*)0x200009cd = 0;
+ *(uint8_t*)0x200009ce = 0;
+ *(uint8_t*)0x200009cf = 0;
+ *(uint8_t*)0x200009d0 = 0;
+ *(uint8_t*)0x200009d1 = 0;
+ *(uint8_t*)0x200009d2 = 0;
+ *(uint8_t*)0x200009d3 = 0;
+ *(uint8_t*)0x200009d4 = 0;
+ *(uint8_t*)0x200009d5 = 0;
+ *(uint8_t*)0x200009d6 = 0;
+ *(uint8_t*)0x200009d7 = 0;
+ *(uint8_t*)0x200009d8 = 0;
+ *(uint8_t*)0x200009d9 = 0;
+ *(uint8_t*)0x200009da = 0;
+ *(uint8_t*)0x200009db = 0;
+ *(uint8_t*)0x200009dc = 0;
+ *(uint8_t*)0x200009dd = 0;
+ *(uint8_t*)0x200009de = 0;
+ *(uint8_t*)0x200009df = 0;
+ *(uint8_t*)0x200009e0 = 0;
+ *(uint8_t*)0x200009e1 = 0;
+ *(uint8_t*)0x200009e2 = 0;
+ *(uint8_t*)0x200009e3 = 0;
+ *(uint8_t*)0x200009e4 = 0;
+ *(uint8_t*)0x200009e5 = 0;
+ *(uint8_t*)0x200009e6 = 0;
+ *(uint8_t*)0x200009e7 = 0;
+ *(uint8_t*)0x200009e8 = 0;
+ *(uint8_t*)0x200009e9 = 0;
+ *(uint8_t*)0x200009ea = 0;
+ *(uint8_t*)0x200009eb = 0;
+ *(uint8_t*)0x200009ec = 0;
+ *(uint8_t*)0x200009ed = 0;
+ *(uint8_t*)0x200009ee = 0;
+ *(uint8_t*)0x200009ef = 0;
+ *(uint8_t*)0x200009f0 = 0;
+ *(uint8_t*)0x200009f1 = 0;
+ *(uint8_t*)0x200009f2 = 0;
+ *(uint8_t*)0x200009f3 = 0;
+ *(uint16_t*)0x200009f4 = 0xc0;
+ *(uint16_t*)0x200009f6 = 0xe8;
+ *(uint32_t*)0x200009f8 = 0;
+ *(uint64_t*)0x20000a00 = 0;
+ *(uint64_t*)0x20000a08 = 0;
+ *(uint16_t*)0x20000a10 = 0x28;
+ memcpy((void*)0x20000a12,
+ "CLASSIFY\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000",
+ 29);
+ *(uint8_t*)0x20000a2f = 0;
+ *(uint32_t*)0x20000a30 = 0;
+ *(uint32_t*)0x20000a38 = htobe32(0xe0000002);
+ *(uint8_t*)0x20000a3c = 0xac;
+ *(uint8_t*)0x20000a3d = 0x1e;
+ *(uint8_t*)0x20000a3e = 0;
+ *(uint8_t*)0x20000a3f = 1;
+ *(uint32_t*)0x20000a40 = htobe32(0);
+ *(uint32_t*)0x20000a44 = htobe32(0);
+ *(uint8_t*)0x20000a48 = 0;
+ *(uint8_t*)0x20000a49 = 0;
+ *(uint8_t*)0x20000a4a = 0;
+ *(uint8_t*)0x20000a4b = 0;
+ *(uint8_t*)0x20000a4c = 0;
+ *(uint8_t*)0x20000a4d = 0;
+ *(uint8_t*)0x20000a4e = 0;
+ *(uint8_t*)0x20000a4f = 0;
+ *(uint8_t*)0x20000a5a = 0;
+ *(uint8_t*)0x20000a5b = 0;
+ *(uint8_t*)0x20000a5c = 0;
+ *(uint8_t*)0x20000a5d = 0;
+ *(uint8_t*)0x20000a5e = 0;
+ *(uint8_t*)0x20000a5f = 0;
+ *(uint8_t*)0x20000a6a = 0;
+ *(uint8_t*)0x20000a6b = 0;
+ *(uint8_t*)0x20000a6c = 0;
+ *(uint8_t*)0x20000a6d = 0;
+ *(uint8_t*)0x20000a6e = 0;
+ *(uint8_t*)0x20000a6f = 0;
+ *(uint8_t*)0x20000a70 = 0;
+ *(uint8_t*)0x20000a71 = 0;
+ *(uint8_t*)0x20000a72 = 0;
+ *(uint8_t*)0x20000a73 = 0;
+ *(uint8_t*)0x20000a74 = 0;
+ *(uint8_t*)0x20000a75 = 0;
+ *(uint8_t*)0x20000a76 = 0;
+ *(uint8_t*)0x20000a77 = 0;
+ *(uint8_t*)0x20000a78 = 0;
+ *(uint8_t*)0x20000a79 = 0;
+ *(uint8_t*)0x20000a7a = 0;
+ *(uint8_t*)0x20000a7b = 0;
+ *(uint8_t*)0x20000a7c = 0;
+ *(uint8_t*)0x20000a7d = 0;
+ *(uint8_t*)0x20000a7e = 0;
+ *(uint8_t*)0x20000a7f = 0;
+ *(uint16_t*)0x20000a8a = htobe16(0);
+ *(uint16_t*)0x20000a8c = htobe16(0);
+ *(uint16_t*)0x20000a8e = htobe16(0);
+ *(uint16_t*)0x20000a90 = htobe16(0x7f);
+ *(uint16_t*)0x20000a92 = htobe16(0);
+ *(uint16_t*)0x20000a94 = htobe16(0);
+ memcpy((void*)0x20000a96,
+ "nr0\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ memcpy((void*)0x20000aa6, "vlan0\000\000\000\000\000\000\000\000\000\000\000",
+ 16);
+ *(uint8_t*)0x20000ab6 = 0;
+ *(uint8_t*)0x20000ac6 = 0;
+ *(uint8_t*)0x20000ad6 = 0;
+ *(uint16_t*)0x20000ad8 = 0;
+ *(uint16_t*)0x20000adc = 0xc0;
+ *(uint16_t*)0x20000ade = 0xe8;
+ *(uint32_t*)0x20000ae0 = 0;
+ *(uint64_t*)0x20000ae8 = 0;
+ *(uint64_t*)0x20000af0 = 0;
+ *(uint16_t*)0x20000af8 = 0x28;
+ memcpy((void*)0x20000afa,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000",
+ 29);
+ *(uint8_t*)0x20000b17 = 0;
+ *(uint32_t*)0x20000b18 = 0xe8;
+ *(uint32_t*)0x20000b20 = htobe32(0xe0000001);
+ *(uint32_t*)0x20000b24 = htobe32(0x7f000001);
+ *(uint32_t*)0x20000b28 = htobe32(0);
+ *(uint32_t*)0x20000b2c = htobe32(0);
+ *(uint8_t*)0x20000b30 = 0;
+ *(uint8_t*)0x20000b31 = 0;
+ *(uint8_t*)0x20000b32 = 0;
+ *(uint8_t*)0x20000b33 = 0;
+ *(uint8_t*)0x20000b34 = 0;
+ *(uint8_t*)0x20000b35 = 0;
+ *(uint8_t*)0x20000b36 = 0;
+ *(uint8_t*)0x20000b37 = 0;
+ *(uint8_t*)0x20000b38 = 0;
+ *(uint8_t*)0x20000b39 = 0;
+ *(uint8_t*)0x20000b3a = 0;
+ *(uint8_t*)0x20000b3b = 0;
+ *(uint8_t*)0x20000b3c = 0;
+ *(uint8_t*)0x20000b3d = 0;
+ *(uint8_t*)0x20000b3e = 0;
+ *(uint8_t*)0x20000b3f = 0;
+ *(uint8_t*)0x20000b40 = 0;
+ *(uint8_t*)0x20000b41 = 0;
+ *(uint8_t*)0x20000b42 = 0;
+ *(uint8_t*)0x20000b43 = -1;
+ *(uint8_t*)0x20000b44 = -1;
+ *(uint8_t*)0x20000b45 = 0;
+ *(uint8_t*)0x20000b46 = 0;
+ *(uint8_t*)0x20000b47 = 0;
+ *(uint8_t*)0x20000b52 = 0xaa;
+ *(uint8_t*)0x20000b53 = 0xaa;
+ *(uint8_t*)0x20000b54 = 0xaa;
+ *(uint8_t*)0x20000b55 = 0xaa;
+ *(uint8_t*)0x20000b56 = 0xaa;
+ *(uint8_t*)0x20000b57 = 0;
+ *(uint8_t*)0x20000b62 = 0;
+ *(uint8_t*)0x20000b63 = 0;
+ *(uint8_t*)0x20000b64 = 0;
+ *(uint8_t*)0x20000b65 = 0;
+ *(uint8_t*)0x20000b66 = 0;
+ *(uint8_t*)0x20000b67 = 0;
+ *(uint16_t*)0x20000b72 = htobe16(0);
+ *(uint16_t*)0x20000b74 = htobe16(0);
+ *(uint16_t*)0x20000b76 = htobe16(0);
+ *(uint16_t*)0x20000b78 = htobe16(5);
+ *(uint16_t*)0x20000b7a = htobe16(0xfffc);
+ *(uint16_t*)0x20000b7c = htobe16(0);
+ memcpy((void*)0x20000b7e, "team0\000\000\000\000\000\000\000\000\000\000\000",
+ 16);
+ memcpy((void*)0x20000b8e, "macvlan1\000\000\000\000\000\000\000\000", 16);
+ *(uint8_t*)0x20000b9e = 0;
+ *(uint8_t*)0x20000bae = 0;
+ *(uint8_t*)0x20000bbe = 0;
+ *(uint16_t*)0x20000bc0 = 0;
+ *(uint16_t*)0x20000bc4 = 0xc0;
+ *(uint16_t*)0x20000bc6 = 0x100;
+ *(uint32_t*)0x20000bc8 = 0;
+ *(uint64_t*)0x20000bd0 = 0;
+ *(uint64_t*)0x20000bd8 = 0;
+ *(uint16_t*)0x20000be0 = 0x40;
+ memcpy((void*)0x20000be2,
+ "RATEEST\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000",
+ 29);
+ *(uint8_t*)0x20000bff = 0;
+ memcpy((void*)0x20000c00,
+ "syz0\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint8_t*)0x20000c10 = 6;
+ *(uint8_t*)0x20000c11 = 1;
+ *(uint64_t*)0x20000c18 = 6;
+ *(uint8_t*)0x20000c20 = 0;
+ *(uint8_t*)0x20000c21 = 0;
+ *(uint8_t*)0x20000c22 = 0;
+ *(uint8_t*)0x20000c23 = 0;
+ *(uint8_t*)0x20000c24 = 0;
+ *(uint8_t*)0x20000c25 = 0;
+ *(uint8_t*)0x20000c26 = 0;
+ *(uint8_t*)0x20000c27 = 0;
+ *(uint8_t*)0x20000c28 = 0;
+ *(uint8_t*)0x20000c29 = 0;
+ *(uint8_t*)0x20000c2a = 0;
+ *(uint8_t*)0x20000c2b = 0;
+ *(uint8_t*)0x20000c2c = 0;
+ *(uint8_t*)0x20000c2d = 0;
+ *(uint8_t*)0x20000c2e = 0;
+ *(uint8_t*)0x20000c2f = 0;
+ *(uint8_t*)0x20000c30 = 0;
+ *(uint8_t*)0x20000c31 = 0;
+ *(uint8_t*)0x20000c32 = 0;
+ *(uint8_t*)0x20000c33 = 0;
+ *(uint8_t*)0x20000c34 = 0;
+ *(uint8_t*)0x20000c35 = 0;
+ *(uint8_t*)0x20000c36 = 0;
+ *(uint8_t*)0x20000c37 = 0;
+ *(uint8_t*)0x20000c38 = 0;
+ *(uint8_t*)0x20000c39 = 0;
+ *(uint8_t*)0x20000c3a = 0;
+ *(uint8_t*)0x20000c3b = 0;
+ *(uint8_t*)0x20000c3c = 0;
+ *(uint8_t*)0x20000c3d = 0;
+ *(uint8_t*)0x20000c3e = 0;
+ *(uint8_t*)0x20000c3f = 0;
+ *(uint8_t*)0x20000c40 = 0;
+ *(uint8_t*)0x20000c41 = 0;
+ *(uint8_t*)0x20000c42 = 0;
+ *(uint8_t*)0x20000c43 = 0;
+ *(uint8_t*)0x20000c44 = 0;
+ *(uint8_t*)0x20000c45 = 0;
+ *(uint8_t*)0x20000c46 = 0;
+ *(uint8_t*)0x20000c47 = 0;
+ *(uint8_t*)0x20000c48 = 0;
+ *(uint8_t*)0x20000c49 = 0;
+ *(uint8_t*)0x20000c4a = 0;
+ *(uint8_t*)0x20000c4b = 0;
+ *(uint8_t*)0x20000c4c = 0;
+ *(uint8_t*)0x20000c4d = 0;
+ *(uint8_t*)0x20000c4e = 0;
+ *(uint8_t*)0x20000c4f = 0;
+ *(uint8_t*)0x20000c50 = 0;
+ *(uint8_t*)0x20000c51 = 0;
+ *(uint8_t*)0x20000c52 = 0;
+ *(uint8_t*)0x20000c53 = 0;
+ *(uint8_t*)0x20000c54 = 0;
+ *(uint8_t*)0x20000c55 = 0;
+ *(uint8_t*)0x20000c56 = 0;
+ *(uint8_t*)0x20000c57 = 0;
+ *(uint8_t*)0x20000c58 = 0;
+ *(uint8_t*)0x20000c59 = 0;
+ *(uint8_t*)0x20000c5a = 0;
+ *(uint8_t*)0x20000c5b = 0;
+ *(uint8_t*)0x20000c5c = 0;
+ *(uint8_t*)0x20000c5d = 0;
+ *(uint8_t*)0x20000c5e = 0;
+ *(uint8_t*)0x20000c5f = 0;
+ *(uint8_t*)0x20000c60 = 0;
+ *(uint8_t*)0x20000c61 = 0;
+ *(uint8_t*)0x20000c62 = 0;
+ *(uint8_t*)0x20000c63 = 0;
+ *(uint8_t*)0x20000c64 = 0;
+ *(uint8_t*)0x20000c65 = 0;
+ *(uint8_t*)0x20000c66 = 0;
+ *(uint8_t*)0x20000c67 = 0;
+ *(uint8_t*)0x20000c68 = 0;
+ *(uint8_t*)0x20000c69 = 0;
+ *(uint8_t*)0x20000c6a = 0;
+ *(uint8_t*)0x20000c6b = 0;
+ *(uint8_t*)0x20000c6c = 0;
+ *(uint8_t*)0x20000c6d = 0;
+ *(uint8_t*)0x20000c6e = 0;
+ *(uint8_t*)0x20000c6f = 0;
+ *(uint8_t*)0x20000c70 = 0;
+ *(uint8_t*)0x20000c71 = 0;
+ *(uint8_t*)0x20000c72 = 0;
+ *(uint8_t*)0x20000c73 = 0;
+ *(uint8_t*)0x20000c74 = 0;
+ *(uint8_t*)0x20000c75 = 0;
+ *(uint8_t*)0x20000c76 = 0;
+ *(uint8_t*)0x20000c77 = 0;
+ *(uint8_t*)0x20000c78 = 0;
+ *(uint8_t*)0x20000c79 = 0;
+ *(uint8_t*)0x20000c7a = 0;
+ *(uint8_t*)0x20000c7b = 0;
+ *(uint8_t*)0x20000c7c = 0;
+ *(uint8_t*)0x20000c7d = 0;
+ *(uint8_t*)0x20000c7e = 0;
+ *(uint8_t*)0x20000c7f = 0;
+ *(uint8_t*)0x20000c80 = 0;
+ *(uint8_t*)0x20000c81 = 0;
+ *(uint8_t*)0x20000c82 = 0;
+ *(uint8_t*)0x20000c83 = 0;
+ *(uint8_t*)0x20000c84 = 0;
+ *(uint8_t*)0x20000c85 = 0;
+ *(uint8_t*)0x20000c86 = 0;
+ *(uint8_t*)0x20000c87 = 0;
+ *(uint8_t*)0x20000c88 = 0;
+ *(uint8_t*)0x20000c89 = 0;
+ *(uint8_t*)0x20000c8a = 0;
+ *(uint8_t*)0x20000c8b = 0;
+ *(uint8_t*)0x20000c8c = 0;
+ *(uint8_t*)0x20000c8d = 0;
+ *(uint8_t*)0x20000c8e = 0;
+ *(uint8_t*)0x20000c8f = 0;
+ *(uint8_t*)0x20000c90 = 0;
+ *(uint8_t*)0x20000c91 = 0;
+ *(uint8_t*)0x20000c92 = 0;
+ *(uint8_t*)0x20000c93 = 0;
+ *(uint8_t*)0x20000c94 = 0;
+ *(uint8_t*)0x20000c95 = 0;
+ *(uint8_t*)0x20000c96 = 0;
+ *(uint8_t*)0x20000c97 = 0;
+ *(uint8_t*)0x20000c98 = 0;
+ *(uint8_t*)0x20000c99 = 0;
+ *(uint8_t*)0x20000c9a = 0;
+ *(uint8_t*)0x20000c9b = 0;
+ *(uint8_t*)0x20000c9c = 0;
+ *(uint8_t*)0x20000c9d = 0;
+ *(uint8_t*)0x20000c9e = 0;
+ *(uint8_t*)0x20000c9f = 0;
+ *(uint8_t*)0x20000ca0 = 0;
+ *(uint8_t*)0x20000ca1 = 0;
+ *(uint8_t*)0x20000ca2 = 0;
+ *(uint8_t*)0x20000ca3 = 0;
+ *(uint8_t*)0x20000ca4 = 0;
+ *(uint8_t*)0x20000ca5 = 0;
+ *(uint8_t*)0x20000ca6 = 0;
+ *(uint8_t*)0x20000ca7 = 0;
+ *(uint8_t*)0x20000ca8 = 0;
+ *(uint8_t*)0x20000ca9 = 0;
+ *(uint8_t*)0x20000caa = 0;
+ *(uint8_t*)0x20000cab = 0;
+ *(uint8_t*)0x20000cac = 0;
+ *(uint8_t*)0x20000cad = 0;
+ *(uint8_t*)0x20000cae = 0;
+ *(uint8_t*)0x20000caf = 0;
+ *(uint8_t*)0x20000cb0 = 0;
+ *(uint8_t*)0x20000cb1 = 0;
+ *(uint8_t*)0x20000cb2 = 0;
+ *(uint8_t*)0x20000cb3 = 0;
+ *(uint8_t*)0x20000cb4 = 0;
+ *(uint8_t*)0x20000cb5 = 0;
+ *(uint8_t*)0x20000cb6 = 0;
+ *(uint8_t*)0x20000cb7 = 0;
+ *(uint8_t*)0x20000cb8 = 0;
+ *(uint8_t*)0x20000cb9 = 0;
+ *(uint8_t*)0x20000cba = 0;
+ *(uint8_t*)0x20000cbb = 0;
+ *(uint8_t*)0x20000cbc = 0;
+ *(uint8_t*)0x20000cbd = 0;
+ *(uint8_t*)0x20000cbe = 0;
+ *(uint8_t*)0x20000cbf = 0;
+ *(uint8_t*)0x20000cc0 = 0;
+ *(uint8_t*)0x20000cc1 = 0;
+ *(uint8_t*)0x20000cc2 = 0;
+ *(uint8_t*)0x20000cc3 = 0;
+ *(uint16_t*)0x20000cc4 = 0xc0;
+ *(uint16_t*)0x20000cc6 = 0xe8;
+ *(uint32_t*)0x20000cc8 = 0;
+ *(uint64_t*)0x20000cd0 = 0;
+ *(uint64_t*)0x20000cd8 = 0;
+ *(uint16_t*)0x20000ce0 = 0x28;
+ memcpy((void*)0x20000ce2,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000",
+ 29);
+ *(uint8_t*)0x20000cff = 0;
+ *(uint32_t*)0x20000d00 = 0xfffffffe;
+ syscall(__NR_setsockopt, r[0], 0xa02000000000000ul, 0x60ul, 0x20000900ul,
+ 0x408ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3c5c8d4347630379dcc10e3d438a1e2f147dcabc.c b/syzkaller-repros/linux/3c5c8d4347630379dcc10e3d438a1e2f147dcabc.c
new file mode 100644
index 0000000..3cb0b83
--- /dev/null
+++ b/syzkaller-repros/linux/3c5c8d4347630379dcc10e3d438a1e2f147dcabc.c
@@ -0,0 +1,636 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+struct csum_inet {
+ uint32_t acc;
+};
+
+static void csum_inet_init(struct csum_inet* csum)
+{
+ csum->acc = 0;
+}
+
+static void csum_inet_update(struct csum_inet* csum, const uint8_t* data,
+ size_t length)
+{
+ if (length == 0)
+ return;
+ size_t i;
+ for (i = 0; i < length - 1; i += 2)
+ csum->acc += *(uint16_t*)&data[i];
+ if (length & 1)
+ csum->acc += (uint16_t)data[length - 1];
+ while (csum->acc > 0xffff)
+ csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16);
+}
+
+static uint16_t csum_inet_digest(struct csum_inet* csum)
+{
+ return ~csum->acc;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+#define MAX_FRAGS 4
+struct vnet_fragmentation {
+ uint32_t full;
+ uint32_t count;
+ uint32_t frags[MAX_FRAGS];
+};
+
+static long syz_emit_ethernet(volatile long a0, volatile long a1,
+ volatile long a2)
+{
+ if (tunfd < 0)
+ return (uintptr_t)-1;
+ uint32_t length = a0;
+ char* data = (char*)a1;
+ struct vnet_fragmentation* frags = (struct vnet_fragmentation*)a2;
+ struct iovec vecs[MAX_FRAGS + 1];
+ uint32_t nfrags = 0;
+ if (!tun_frags_enabled || frags == NULL) {
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = length;
+ nfrags++;
+ } else {
+ bool full = true;
+ uint32_t i, count = 0;
+ full = frags->full;
+ count = frags->count;
+ if (count > MAX_FRAGS)
+ count = MAX_FRAGS;
+ for (i = 0; i < count && length != 0; i++) {
+ uint32_t size = 0;
+ size = frags->frags[i];
+ if (size > length)
+ size = length;
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = size;
+ nfrags++;
+ data += size;
+ length -= size;
+ }
+ if (length != 0 && (full || nfrags == 0)) {
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = length;
+ nfrags++;
+ }
+ }
+ return writev(tunfd, vecs, nfrags);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000180 = 6;
+ *(uint32_t*)0x20000184 = 4;
+ *(uint64_t*)0x20000188 = 0x20000200;
+ *(uint8_t*)0x20000200 = 0x18;
+ STORE_BY_BITMASK(uint8_t, , 0x20000201, 2, 0, 4);
+ STORE_BY_BITMASK(uint8_t, , 0x20000201, 0, 4, 4);
+ *(uint16_t*)0x20000202 = 0;
+ *(uint32_t*)0x20000204 = 0;
+ *(uint8_t*)0x20000208 = 0;
+ *(uint8_t*)0x20000209 = 0;
+ *(uint16_t*)0x2000020a = 0;
+ *(uint32_t*)0x2000020c = 0;
+ *(uint8_t*)0x20000210 = 0x85;
+ *(uint8_t*)0x20000211 = 0;
+ *(uint16_t*)0x20000212 = 0;
+ *(uint32_t*)0x20000214 = 0x2c;
+ *(uint8_t*)0x20000218 = 0x95;
+ *(uint8_t*)0x20000219 = 0;
+ *(uint16_t*)0x2000021a = 0;
+ *(uint32_t*)0x2000021c = 0;
+ *(uint64_t*)0x20000190 = 0x200000c0;
+ memcpy((void*)0x200000c0, "GPL\000", 4);
+ *(uint32_t*)0x20000198 = 4;
+ *(uint32_t*)0x2000019c = 0x1000;
+ *(uint64_t*)0x200001a0 = 0x2062b000;
+ *(uint32_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001ac = 0;
+ *(uint8_t*)0x200001b0 = 0;
+ *(uint8_t*)0x200001b1 = 0;
+ *(uint8_t*)0x200001b2 = 0;
+ *(uint8_t*)0x200001b3 = 0;
+ *(uint8_t*)0x200001b4 = 0;
+ *(uint8_t*)0x200001b5 = 0;
+ *(uint8_t*)0x200001b6 = 0;
+ *(uint8_t*)0x200001b7 = 0;
+ *(uint8_t*)0x200001b8 = 0;
+ *(uint8_t*)0x200001b9 = 0;
+ *(uint8_t*)0x200001ba = 0;
+ *(uint8_t*)0x200001bb = 0;
+ *(uint8_t*)0x200001bc = 0;
+ *(uint8_t*)0x200001bd = 0;
+ *(uint8_t*)0x200001be = 0;
+ *(uint8_t*)0x200001bf = 0;
+ *(uint32_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c4 = 0;
+ *(uint32_t*)0x200001c8 = -1;
+ *(uint32_t*)0x200001cc = 8;
+ *(uint64_t*)0x200001d0 = 0;
+ *(uint32_t*)0x200001d8 = 0;
+ *(uint32_t*)0x200001dc = 0x10;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint32_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001ec = 0;
+ *(uint32_t*)0x200001f0 = -1;
+ res = syscall(__NR_bpf, 5ul, 0x20000180ul, 0x70ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0x20000080;
+ *(uint64_t*)0x20000080 = 0x20000040;
+ *(uint32_t*)0x20000040 = 0x34;
+ *(uint16_t*)0x20000044 = 0x10;
+ *(uint16_t*)0x20000046 = 0x801;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint8_t*)0x20000050 = 0;
+ *(uint8_t*)0x20000051 = 0;
+ *(uint16_t*)0x20000052 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint16_t*)0x20000060 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000062, 0x2b, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000063, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000063, 1, 7, 1);
+ *(uint16_t*)0x20000064 = 8;
+ *(uint16_t*)0x20000066 = 1;
+ *(uint32_t*)0x20000068 = r[1];
+ *(uint16_t*)0x2000006c = 8;
+ *(uint16_t*)0x2000006e = 0x1b;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint64_t*)0x20000088 = 0x34;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0x300000000000000;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000140ul, 0ul);
+ *(uint8_t*)0x20000100 = 0xaa;
+ *(uint8_t*)0x20000101 = 0xaa;
+ *(uint8_t*)0x20000102 = 0xaa;
+ *(uint8_t*)0x20000103 = 0xaa;
+ *(uint8_t*)0x20000104 = 0xaa;
+ *(uint8_t*)0x20000105 = 0xaa;
+ *(uint8_t*)0x20000106 = 0xaa;
+ *(uint8_t*)0x20000107 = 0xaa;
+ *(uint8_t*)0x20000108 = 0xaa;
+ *(uint8_t*)0x20000109 = 0xaa;
+ *(uint8_t*)0x2000010a = 0xaa;
+ *(uint8_t*)0x2000010b = 0;
+ *(uint16_t*)0x2000010c = htobe16(0x86dd);
+ STORE_BY_BITMASK(uint8_t, , 0x2000010e, 0, 0, 4);
+ STORE_BY_BITMASK(uint8_t, , 0x2000010e, 6, 4, 4);
+ memcpy((void*)0x2000010f, "\x20\x92\x00", 3);
+ *(uint16_t*)0x20000112 = htobe16(0x18);
+ *(uint8_t*)0x20000114 = 6;
+ *(uint8_t*)0x20000115 = 0;
+ *(uint8_t*)0x20000116 = 0;
+ *(uint8_t*)0x20000117 = 0;
+ *(uint8_t*)0x20000118 = 0;
+ *(uint8_t*)0x20000119 = 0;
+ *(uint8_t*)0x2000011a = 0;
+ *(uint8_t*)0x2000011b = 0;
+ *(uint8_t*)0x2000011c = 0;
+ *(uint8_t*)0x2000011d = 0;
+ *(uint8_t*)0x2000011e = 0;
+ *(uint8_t*)0x2000011f = 0;
+ *(uint8_t*)0x20000120 = 0;
+ *(uint8_t*)0x20000121 = 0;
+ *(uint8_t*)0x20000122 = 0;
+ *(uint8_t*)0x20000123 = 0;
+ *(uint8_t*)0x20000124 = 0;
+ *(uint8_t*)0x20000125 = 0;
+ *(uint8_t*)0x20000126 = 0xfe;
+ *(uint8_t*)0x20000127 = 0x80;
+ *(uint8_t*)0x20000128 = 0;
+ *(uint8_t*)0x20000129 = 0;
+ *(uint8_t*)0x2000012a = 0;
+ *(uint8_t*)0x2000012b = 0;
+ *(uint8_t*)0x2000012c = 0;
+ *(uint8_t*)0x2000012d = 0;
+ *(uint8_t*)0x2000012e = 0;
+ *(uint8_t*)0x2000012f = 0;
+ *(uint8_t*)0x20000130 = 0;
+ *(uint8_t*)0x20000131 = 0;
+ *(uint8_t*)0x20000132 = 0;
+ *(uint8_t*)0x20000133 = 0;
+ *(uint8_t*)0x20000134 = 0;
+ *(uint8_t*)0x20000135 = 0xaa;
+ *(uint16_t*)0x20000136 = htobe16(0);
+ *(uint16_t*)0x20000138 = htobe16(0x4e22);
+ *(uint32_t*)0x2000013a = 0x41424344;
+ *(uint32_t*)0x2000013e = 0x41424344;
+ STORE_BY_BITMASK(uint8_t, , 0x20000142, 0, 0, 1);
+ STORE_BY_BITMASK(uint8_t, , 0x20000142, 0, 1, 3);
+ STORE_BY_BITMASK(uint8_t, , 0x20000142, 6, 4, 4);
+ *(uint8_t*)0x20000143 = 0xc2;
+ *(uint16_t*)0x20000144 = htobe16(0);
+ *(uint16_t*)0x20000146 = htobe16(0);
+ *(uint16_t*)0x20000148 = htobe16(0);
+ *(uint8_t*)0x2000014a = 6;
+ *(uint8_t*)0x2000014b = 2;
+ struct csum_inet csum_1;
+ csum_inet_init(&csum_1);
+ csum_inet_update(&csum_1, (const uint8_t*)0x20000116, 16);
+ csum_inet_update(&csum_1, (const uint8_t*)0x20000126, 16);
+ uint32_t csum_1_chunk_2 = 0x18000000;
+ csum_inet_update(&csum_1, (const uint8_t*)&csum_1_chunk_2, 4);
+ uint32_t csum_1_chunk_3 = 0x6000000;
+ csum_inet_update(&csum_1, (const uint8_t*)&csum_1_chunk_3, 4);
+ csum_inet_update(&csum_1, (const uint8_t*)0x20000136, 24);
+ *(uint16_t*)0x20000146 = csum_inet_digest(&csum_1);
+ syz_emit_ethernet(0x4e, 0x20000100, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3c6d2a9de226763e8c607f53d500aab01b639f2e.c b/syzkaller-repros/linux/3c6d2a9de226763e8c607f53d500aab01b639f2e.c
new file mode 100644
index 0000000..7c9c729
--- /dev/null
+++ b/syzkaller-repros/linux/3c6d2a9de226763e8c607f53d500aab01b639f2e.c
@@ -0,0 +1,2063 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 7; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+#ifndef __NR_seccomp
+#define __NR_seccomp 317
+#endif
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ NONFAILING(*(uint16_t*)0x200001c0 = 1);
+ NONFAILING(*(uint64_t*)0x200001c8 = 0x20000080);
+ NONFAILING(*(uint16_t*)0x20000080 = 6);
+ NONFAILING(*(uint8_t*)0x20000082 = 0);
+ NONFAILING(*(uint8_t*)0x20000083 = 0);
+ NONFAILING(*(uint32_t*)0x20000084 = 0x7ffffffb);
+ res = syscall(__NR_seccomp, 1ul, 0xcul, 0x200001c0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_ioctl, r[0], 0xc0182101ul, 0ul);
+ break;
+ case 2:
+ NONFAILING(memcpy((void*)0x20000080, "/dev/ion\000", 9));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000080ul, 0ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ NONFAILING(*(uint64_t*)0x20000200 = 0x80033d);
+ NONFAILING(*(uint32_t*)0x20000208 = 0x209);
+ NONFAILING(*(uint32_t*)0x2000020c = 0);
+ NONFAILING(*(uint32_t*)0x20000210 = -1);
+ NONFAILING(*(uint32_t*)0x20000214 = 0);
+ res = syscall(__NR_ioctl, r[1], 0xc0184900ul, 0x20000200ul);
+ if (res != -1)
+ NONFAILING(r[2] = *(uint32_t*)0x20000210);
+ break;
+ case 4:
+ res = syscall(__NR_dup2, r[1], r[2]);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 5:
+ NONFAILING(*(uint64_t*)0x20000200 = 0x80033d);
+ NONFAILING(*(uint32_t*)0x20000208 = 0x221);
+ NONFAILING(*(uint32_t*)0x2000020c = 0);
+ NONFAILING(*(uint32_t*)0x20000210 = -1);
+ NONFAILING(*(uint32_t*)0x20000214 = 0);
+ syscall(__NR_ioctl, r[3], 0xc0184900ul, 0x20000200ul);
+ break;
+ case 6:
+ NONFAILING(*(uint32_t*)0x20000140 = 0xe);
+ NONFAILING(*(uint16_t*)0x20000144 = 0x18);
+ NONFAILING(*(uint16_t*)0x20000146 = 0xfa00);
+ NONFAILING(*(uint64_t*)0x20000148 = 0x20000040);
+ NONFAILING(*(uint32_t*)0x20000040 = 1);
+ NONFAILING(*(uint32_t*)0x20000150 = -1);
+ NONFAILING(*(uint32_t*)0x20000154 = 0);
+ NONFAILING(*(uint32_t*)0x20000158 = 2);
+ NONFAILING(*(uint32_t*)0x2000015c = 4);
+ syscall(__NR_write, r[3], 0x20000140ul, 0x20ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ install_segv_handler();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3d08e189dea3e9ebfeb32a6c4a1447ad83441556.c b/syzkaller-repros/linux/3d08e189dea3e9ebfeb32a6c4a1447ad83441556.c
new file mode 100644
index 0000000..fd8f9d2
--- /dev/null
+++ b/syzkaller-repros/linux/3d08e189dea3e9ebfeb32a6c4a1447ad83441556.c
@@ -0,0 +1,875 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ exit(1);
+ }
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x200000c0, "memory.current\000", 15);
+ res = syscall(__NR_openat, 0xffffff9c, 0x200000c0ul, 0x26e1ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000144 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint32_t*)0x2000014c = 0;
+ *(uint32_t*)0x20000150 = 0;
+ *(uint8_t*)0x20000154 = 0;
+ *(uint8_t*)0x20000155 = 0;
+ *(uint8_t*)0x20000156 = 0;
+ *(uint8_t*)0x20000157 = 0;
+ *(uint8_t*)0x20000158 = 0;
+ *(uint8_t*)0x20000159 = 0;
+ *(uint8_t*)0x2000015a = 0;
+ *(uint8_t*)0x2000015b = 0;
+ syscall(__NR_ioctl, r[0], 0x40086602ul, 0x20000140ul);
+ sprintf((char*)0x20000080, "0x%016llx", (long long)0);
+ syscall(__NR_write, r[0], 0x20000080ul, 0x87f1a7ul);
+ syscall(__NR_ioctl, r[0], 0xc020660bul, 0ul);
+ syscall(__NR_ioctl, r[0], 0x6609ul, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3d6afd8470840e9145db28cc425fea4238c34d14.c b/syzkaller-repros/linux/3d6afd8470840e9145db28cc425fea4238c34d14.c
new file mode 100644
index 0000000..ba5c045
--- /dev/null
+++ b/syzkaller-repros/linux/3d6afd8470840e9145db28cc425fea4238c34d14.c
@@ -0,0 +1,316 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/dri/card#\000", 15);
+ res = syz_open_dev(0x20000000, 1, 0);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000140, "/dev/ion\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000140ul, 0ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000040 = 0xa925;
+ *(uint32_t*)0x20000048 = 1;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = -1;
+ *(uint32_t*)0x20000054 = 0;
+ res = syscall(__NR_ioctl, r[1], 0xc0184900ul, 0x20000040ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000050;
+ res = syscall(__NR_dup, r[2]);
+ if (res != -1)
+ r[3] = res;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = r[3];
+ syscall(__NR_ioctl, r[0], 0xc00c642eul, 0x200000c0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3fc16c8757592a555c9b2faa8757f60d2bdcaacc.c b/syzkaller-repros/linux/3fc16c8757592a555c9b2faa8757f60d2bdcaacc.c
new file mode 100644
index 0000000..44b01b7
--- /dev/null
+++ b/syzkaller-repros/linux/3fc16c8757592a555c9b2faa8757f60d2bdcaacc.c
@@ -0,0 +1,132 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000000, "./cgroup.cpu/syz0", 18);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000000, 0x200002, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_flock, r[0], 0xe);
+ break;
+ case 2:
+ memcpy((void*)0x20000040, "syz0", 5);
+ syscall(__NR_mkdirat, -1, 0x20000040, 0x1ff);
+ break;
+ case 3:
+ syscall(__NR_mincore, 0x20ffa000, 0x3000, 0x200000c0);
+ break;
+ case 4:
+ syscall(__NR_ioctl, -1, 0x5425, 0x81);
+ break;
+ case 5:
+ memcpy((void*)0x20000080, "/dev/ptmx", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000080, 0x400000, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 6:
+ *(uint64_t*)0x20001540 = 0x20000180;
+ *(uint64_t*)0x20001548 = 0xe3;
+ *(uint64_t*)0x20001550 = 0x20000280;
+ *(uint64_t*)0x20001558 = 0xaf;
+ *(uint64_t*)0x20001560 = 0x20000340;
+ *(uint64_t*)0x20001568 = 0x7a;
+ *(uint64_t*)0x20001570 = 0x200003c0;
+ *(uint64_t*)0x20001578 = 0x23;
+ *(uint64_t*)0x20001580 = 0x20000400;
+ *(uint64_t*)0x20001588 = 0x23;
+ *(uint64_t*)0x20001590 = 0x20000440;
+ *(uint64_t*)0x20001598 = 0xda;
+ *(uint64_t*)0x200015a0 = 0x20000540;
+ *(uint64_t*)0x200015a8 = 0x1000;
+ syscall(__NR_readv, r[1], 0x20001540, 7);
+ break;
+ }
+}
+
+void loop()
+{
+ execute(7);
+ collide = 1;
+ execute(7);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/3ff0b1f7b903343c85ebcd159a6aa4f7916fd7ea.c b/syzkaller-repros/linux/3ff0b1f7b903343c85ebcd159a6aa4f7916fd7ea.c
new file mode 100644
index 0000000..9c66417
--- /dev/null
+++ b/syzkaller-repros/linux/3ff0b1f7b903343c85ebcd159a6aa4f7916fd7ea.c
@@ -0,0 +1,1475 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0xa, 1, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ NONFAILING(*(uint32_t*)0x200000c0 = 1);
+ syscall(__NR_setsockopt, r[0], 6, 0x13, 0x200000c0, 0x151);
+ break;
+ case 2:
+ NONFAILING(*(uint16_t*)0x20000140 = 0xa);
+ NONFAILING(*(uint16_t*)0x20000142 = htobe16(0));
+ NONFAILING(*(uint32_t*)0x20000144 = htobe32(0));
+ NONFAILING(*(uint8_t*)0x20000148 = 0);
+ NONFAILING(*(uint8_t*)0x20000149 = 0);
+ NONFAILING(*(uint8_t*)0x2000014a = 0);
+ NONFAILING(*(uint8_t*)0x2000014b = 0);
+ NONFAILING(*(uint8_t*)0x2000014c = 0);
+ NONFAILING(*(uint8_t*)0x2000014d = 0);
+ NONFAILING(*(uint8_t*)0x2000014e = 0);
+ NONFAILING(*(uint8_t*)0x2000014f = 0);
+ NONFAILING(*(uint8_t*)0x20000150 = 0);
+ NONFAILING(*(uint8_t*)0x20000151 = 0);
+ NONFAILING(*(uint8_t*)0x20000152 = -1);
+ NONFAILING(*(uint8_t*)0x20000153 = -1);
+ NONFAILING(*(uint8_t*)0x20000154 = 0xac);
+ NONFAILING(*(uint8_t*)0x20000155 = 0x14);
+ NONFAILING(*(uint8_t*)0x20000156 = 0x14);
+ NONFAILING(*(uint8_t*)0x20000157 = 0x17);
+ NONFAILING(*(uint32_t*)0x20000158 = 0);
+ syscall(__NR_connect, r[0], 0x20000140, 0x1c);
+ break;
+ case 3:
+ NONFAILING(*(uint32_t*)0x20000240 = 2);
+ syscall(__NR_setsockopt, r[0], 0x29, 1, 0x20000240, 4);
+ break;
+ case 4:
+ NONFAILING(memcpy((void*)0x20000080, "tls\000", 4));
+ syscall(__NR_setsockopt, r[0], 6, 0x1f, 0x20000080, 0x9f);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_binfmt_misc();
+ setup_leak();
+ install_segv_handler();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/414fc48eb66fb163fb987719fa8c26bb286bef1c.c b/syzkaller-repros/linux/414fc48eb66fb163fb987719fa8c26bb286bef1c.c
new file mode 100644
index 0000000..565714e
--- /dev/null
+++ b/syzkaller-repros/linux/414fc48eb66fb163fb987719fa8c26bb286bef1c.c
@@ -0,0 +1,205 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+}
+
+#define SYZ_HAVE_RESET_TEST 1
+static void reset_test()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ reset_test();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ long res = 0;
+ memcpy((void*)0x20000040, "/dev/media#", 12);
+ res = syz_open_dev(0x20000040, 0xffffffffffffb267, 0x100);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x5646, 0);
+ memcpy((void*)0x200000c0, "/dev/video#", 12);
+ res = syz_open_dev(0x200000c0, 3, 0);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_ioctl, r[1], 0x5646, 0);
+ syscall(__NR_read, r[1], 0x20000000, 0x74);
+ memcpy((void*)0x20000240, "/dev/media#", 12);
+ res = syz_open_dev(0x20000240, 0x8c, 0x10900);
+ if (res != -1)
+ r[2] = res;
+ memcpy((void*)0x20000600, "/dev/v4l-subdev#", 17);
+ res = syz_open_dev(0x20000600, 0x1ff, 0x400000);
+ if (res != -1)
+ r[3] = res;
+ *(uint32_t*)0x20000680 = 4;
+ *(uint32_t*)0x20000684 = 4;
+ *(uint32_t*)0x20000688 = 0x2e3f;
+ *(uint32_t*)0x2000068c = 0;
+ *(uint32_t*)0x20000690 = 0;
+ *(uint32_t*)0x20000694 = 0;
+ *(uint32_t*)0x20000698 = 0;
+ *(uint32_t*)0x2000069c = 0;
+ *(uint32_t*)0x200006a0 = 0;
+ *(uint32_t*)0x200006a4 = 0;
+ *(uint32_t*)0x200006a8 = 0;
+ syscall(__NR_ioctl, -1, 0x402c5639, 0x20000680);
+ *(uint32_t*)0x20000780 = 0x9a0000;
+ *(uint32_t*)0x20000784 = 0xdb;
+ *(uint32_t*)0x20000788 = 8;
+ *(uint32_t*)0x2000078c = 0;
+ *(uint32_t*)0x20000790 = 0;
+ *(uint64_t*)0x20000798 = 0x20000740;
+ *(uint32_t*)0x20000740 = 0x9b0bf7;
+ *(uint32_t*)0x20000744 = 0x400;
+ *(uint32_t*)0x20000748 = 0;
+ *(uint64_t*)0x2000074c = 0x100;
+ syscall(__NR_ioctl, r[3], 0xc0205648, 0x20000780);
+ syscall(__NR_ioctl, r[2], 0x8818564c, 0x20000800);
+ *(uint32_t*)0x20001240 = 0xb;
+ *(uint32_t*)0x20001244 = 0x10000;
+ *(uint32_t*)0x20001248 = 0xfff;
+ *(uint32_t*)0x2000124c = 0xfff;
+ *(uint32_t*)0x20001250 = 9;
+ syscall(__NR_ioctl, -1, 0xc014563b, 0x20001240);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/41ef72eead121f7189d1cbd590622f386a40e2b3.c b/syzkaller-repros/linux/41ef72eead121f7189d1cbd590622f386a40e2b3.c
new file mode 100644
index 0000000..8500719
--- /dev/null
+++ b/syzkaller-repros/linux/41ef72eead121f7189d1cbd590622f386a40e2b3.c
@@ -0,0 +1,695 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0x0};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x11ul, 3ul, 0x300ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20006ffc = 0x4000203;
+ syscall(__NR_setsockopt, r[0], 0x107ul, 0x14ul, 0x20006ffcul, 4ul);
+ res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000040,
+ "hsr0\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20000050 = 0;
+ res = syscall(__NR_ioctl, r[1], 0x8933ul, 0x20000040ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000050;
+ *(uint16_t*)0x20000000 = 0x11;
+ *(uint16_t*)0x20000002 = htobe16(0x17);
+ *(uint32_t*)0x20000004 = r[2];
+ *(uint16_t*)0x20000008 = 1;
+ *(uint8_t*)0x2000000a = 0;
+ *(uint8_t*)0x2000000b = 6;
+ *(uint8_t*)0x2000000c = 0xaa;
+ *(uint8_t*)0x2000000d = 0xaa;
+ *(uint8_t*)0x2000000e = 0xaa;
+ *(uint8_t*)0x2000000f = 0xaa;
+ *(uint8_t*)0x20000010 = 0xaa;
+ *(uint8_t*)0x20000011 = 0xbb;
+ *(uint8_t*)0x20000012 = 0;
+ *(uint8_t*)0x20000013 = 0;
+ syscall(__NR_bind, r[0], 0x20000000ul, 0x14ul);
+ memcpy((void*)0x20000100,
+ "\x05\x03\x0e\x00\x40\x06\x3e\x00\x00\x00\x02\x00\xc5\x2c", 14);
+ syscall(__NR_sendto, r[0], 0x20000100ul, 0xeul, 0ul, 0ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/424f2cad4cbb77db7834a34e22b06b0a5e02414e.c b/syzkaller-repros/linux/424f2cad4cbb77db7834a34e22b06b0a5e02414e.c
new file mode 100644
index 0000000..babfdaf
--- /dev/null
+++ b/syzkaller-repros/linux/424f2cad4cbb77db7834a34e22b06b0a5e02414e.c
@@ -0,0 +1,723 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 14; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[5] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syz_open_dev(0xc, 4, 3);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_socketpair, 1ul, 1ul, 0ul, 0ul);
+ break;
+ case 2:
+ res = syscall(__NR_socket, 2ul, 1ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ syscall(__NR_setsockopt, r[1], 0ul, 0x27ul, 0ul, 0ul);
+ break;
+ case 4:
+ syscall(__NR_setsockopt, -1, 0ul, 0x29ul, 0ul, 0ul);
+ break;
+ case 5:
+ res = syscall(__NR_dup2, -1, r[1]);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 6:
+ syscall(__NR_socketpair, 1ul, 1ul, 0ul, 0ul);
+ break;
+ case 7:
+ syscall(__NR_getsockopt, r[2], 0x84ul, 0x11ul, 0ul, 0ul);
+ break;
+ case 8:
+ syscall(__NR_setsockopt, r[1], 0x84ul, 0x78ul, 0ul, 0ul);
+ break;
+ case 9:
+ res = syscall(__NR_socket, 2ul, 1ul, 0ul);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 10:
+ syscall(__NR_setsockopt, r[3], 0ul, 0x27ul, 0ul, 0ul);
+ break;
+ case 11:
+ syscall(__NR_ioctl, r[0], 0x5437ul, 0ul);
+ break;
+ case 12:
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 13:
+ syscall(__NR_ioctl, r[4], 0x5608ul, 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/439c37d288d4f26a33a6c7e5c57a97791453a447.c b/syzkaller-repros/linux/439c37d288d4f26a33a6c7e5c57a97791453a447.c
new file mode 100644
index 0000000..d587316
--- /dev/null
+++ b/syzkaller-repros/linux/439c37d288d4f26a33a6c7e5c57a97791453a447.c
@@ -0,0 +1,102 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000000, "/dev/ptmx", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000000, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_munmap, 0x20000000, 0x1000);
+ break;
+ case 2:
+ syscall(__NR_read, r[0], 0x20000040, 0x75);
+ break;
+ }
+}
+
+void loop()
+{
+ execute(3);
+ collide = 1;
+ execute(3);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/445ad4be0c26e28632b61b00cb4eb31ccd6de6a7.c b/syzkaller-repros/linux/445ad4be0c26e28632b61b00cb4eb31ccd6de6a7.c
new file mode 100644
index 0000000..25d017d
--- /dev/null
+++ b/syzkaller-repros/linux/445ad4be0c26e28632b61b00cb4eb31ccd6de6a7.c
@@ -0,0 +1,1040 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20001880,
+ "wg0\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20001890 = 0;
+ syscall(__NR_ioctl, r[0], 0x8922ul, 0x20001880ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/44793a1c21e8a3df44df46ddf00d44ea0328c0c1.c b/syzkaller-repros/linux/44793a1c21e8a3df44df46ddf00d44ea0328c0c1.c
new file mode 100644
index 0000000..fed1295
--- /dev/null
+++ b/syzkaller-repros/linux/44793a1c21e8a3df44df46ddf00d44ea0328c0c1.c
@@ -0,0 +1,435 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000240, "/dev/i2c-#\000", 11);
+ res = syz_open_dev(0x20000240, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x200000c0 = 0;
+ *(uint8_t*)0x200000c1 = 0;
+ *(uint32_t*)0x200000c4 = 2;
+ *(uint64_t*)0x200000c8 = 0x20000080;
+ *(uint8_t*)0x20000080 = 0;
+ memcpy((void*)0x20000081,
+ "\xa0\x91\xe2\x74\x2c\x41\x9c\xc7\x77\x1c\x34\x0a\xa8\x41\x2c\xa8\xe8"
+ "\x19\x71\xd2\x5b\x63\xf8\x99\x49\x99\x10\x7e\x2b\x7f\xed\xcf\x84",
+ 33);
+ syscall(__NR_ioctl, r[0], 0x720ul, 0x200000c0ul);
+ *(uint8_t*)0x20000240 = 0;
+ *(uint8_t*)0x20000241 = 0xdf;
+ *(uint32_t*)0x20000244 = 8;
+ *(uint64_t*)0x20000248 = 0x20000200;
+ *(uint8_t*)0x20000200 = 0x22;
+ memcpy((void*)0x20000201,
+ "\xb8\x29\x22\x2c\x32\x44\x6c\xa8\x68\x69\x30\x42\x29\x6b\xd0\xfc\x96"
+ "\x38\x9d\x53\x52\xf1\x74\xf1\xb7\x77\xe6\x69\xcd\xd0\x8e\x01\x83",
+ 33);
+ syscall(__NR_ioctl, r[0], 0x720ul, 0x20000240ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/466d10a4af6d0a7a4eec73bfba056d0002bd6711.c b/syzkaller-repros/linux/466d10a4af6d0a7a4eec73bfba056d0002bd6711.c
new file mode 100644
index 0000000..e44a9a1
--- /dev/null
+++ b/syzkaller-repros/linux/466d10a4af6d0a7a4eec73bfba056d0002bd6711.c
@@ -0,0 +1,730 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ NONFAILING(memcpy((void*)0x200001c0, "/dev/nbd#\000", 10));
+ syz_open_dev(0x200001c0, 0, 0);
+ res = syz_open_dev(0, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ res = syscall(__NR_socket, 2ul, 1ul, 0);
+ if (res != -1)
+ r[1] = res;
+ res = syz_open_dev(0, 0, 0);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_ioctl, r[2], 0xab00ul, r[1]);
+ syscall(__NR_ioctl, r[0], 0xab03ul, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/46987d0994ee4a9af198f5db904b984f9b2c16b9.c b/syzkaller-repros/linux/46987d0994ee4a9af198f5db904b984f9b2c16b9.c
new file mode 100644
index 0000000..750530d
--- /dev/null
+++ b/syzkaller-repros/linux/46987d0994ee4a9af198f5db904b984f9b2c16b9.c
@@ -0,0 +1,250 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1)
+
+#define BITMASK_LEN_OFF(type, bf_off, bf_len) \
+ (type)(BITMASK_LEN(type, (bf_len)) << (bf_off))
+
+#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \
+ if ((bf_off) == 0 && (bf_len) == 0) { \
+ *(type*)(addr) = (type)(val); \
+ } else { \
+ type new_val = *(type*)(addr); \
+ new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \
+ new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \
+ *(type*)(addr) = new_val; \
+ }
+
+static void execute_one();
+extern unsigned long long procid;
+
+void loop()
+{
+ while (1) {
+ execute_one();
+ }
+}
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[4] = {0x0, 0x0, 0xffffffffffffffff, 0x0};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_clock_gettime, 0, 0x20001ac0);
+ if (res != -1) {
+ r[0] = *(uint64_t*)0x20001ac0;
+ r[1] = *(uint64_t*)0x20001ac8;
+ }
+ break;
+ case 1:
+ *(uint64_t*)0x20001a00 = 0;
+ *(uint32_t*)0x20001a08 = 0;
+ *(uint64_t*)0x20001a10 = 0x20000040;
+ *(uint64_t*)0x20000040 = 0x20000100;
+ *(uint64_t*)0x20000048 = 0x61;
+ *(uint64_t*)0x20000050 = 0x20000180;
+ *(uint64_t*)0x20000058 = 0xb0;
+ *(uint64_t*)0x20000060 = 0x20000240;
+ *(uint64_t*)0x20000068 = 0xce;
+ *(uint64_t*)0x20000070 = 0x20000340;
+ *(uint64_t*)0x20000078 = 0x7a;
+ *(uint64_t*)0x20001a18 = 4;
+ *(uint64_t*)0x20001a20 = 0x200003c0;
+ *(uint64_t*)0x20001a28 = 0x6d;
+ *(uint32_t*)0x20001a30 = 0x101;
+ *(uint32_t*)0x20001a38 = 0xfffffc01;
+ *(uint64_t*)0x20001a40 = 0;
+ *(uint32_t*)0x20001a48 = 0;
+ *(uint64_t*)0x20001a50 = 0x20000580;
+ *(uint64_t*)0x20000580 = 0x20000440;
+ *(uint64_t*)0x20000588 = 0xbd;
+ *(uint64_t*)0x20000590 = 0x20000500;
+ *(uint64_t*)0x20000598 = 0x70;
+ *(uint64_t*)0x20001a58 = 2;
+ *(uint64_t*)0x20001a60 = 0x200005c0;
+ *(uint64_t*)0x20001a68 = 0xf0;
+ *(uint32_t*)0x20001a70 = 8;
+ *(uint32_t*)0x20001a78 = 0xc2;
+ *(uint64_t*)0x20001a80 = 0x200006c0;
+ *(uint32_t*)0x20001a88 = 0x80;
+ *(uint64_t*)0x20001a90 = 0x20001900;
+ *(uint64_t*)0x20001900 = 0x20000740;
+ *(uint64_t*)0x20001908 = 0x1000;
+ *(uint64_t*)0x20001910 = 0x20001740;
+ *(uint64_t*)0x20001918 = 0x86;
+ *(uint64_t*)0x20001920 = 0x20001800;
+ *(uint64_t*)0x20001928 = 0x72;
+ *(uint64_t*)0x20001930 = 0x20001880;
+ *(uint64_t*)0x20001938 = 0x52;
+ *(uint64_t*)0x20001a98 = 4;
+ *(uint64_t*)0x20001aa0 = 0x20001940;
+ *(uint64_t*)0x20001aa8 = 0xa6;
+ *(uint32_t*)0x20001ab0 = 0x8001;
+ *(uint32_t*)0x20001ab8 = 9;
+ *(uint64_t*)0x20001b00 = r[0];
+ *(uint64_t*)0x20001b08 = r[1] + 30000000;
+ res =
+ syscall(__NR_recvmmsg, 0xffffff9c, 0x20001a00, 3, 0x10000, 0x20001b00);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x200006ca;
+ break;
+ case 2:
+ *(uint32_t*)0x20001b40 = 7;
+ syscall(__NR_setsockopt, r[2], 0x11, 0x64, 0x20001b40, 4);
+ break;
+ case 3:
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0x70;
+ *(uint8_t*)0x20000088 = 0;
+ *(uint8_t*)0x20000089 = 0;
+ *(uint8_t*)0x2000008a = 0;
+ *(uint8_t*)0x2000008b = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint64_t*)0x20000090 = 0x7fff;
+ *(uint64_t*)0x20000098 = 0;
+ *(uint64_t*)0x200000a0 = 0;
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 0, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 1, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 2, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 3, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 4, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 5, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 6, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 7, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 8, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 9, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 10, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 11, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 12, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 13, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 14, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 15, 2);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 17, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 18, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 19, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 20, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 21, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 22, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 23, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 24, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 25, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 26, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 27, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 28, 1);
+ STORE_BY_BITMASK(uint64_t, 0x200000a8, 0, 29, 35);
+ *(uint32_t*)0x200000b0 = 0;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint64_t*)0x200000b8 = 0x20000000;
+ *(uint64_t*)0x200000c0 = 0;
+ *(uint64_t*)0x200000c8 = 0;
+ *(uint64_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ *(uint64_t*)0x200000e0 = 0;
+ *(uint32_t*)0x200000e8 = 0;
+ *(uint16_t*)0x200000ec = 0;
+ *(uint16_t*)0x200000ee = 0;
+ syscall(__NR_perf_event_open, 0x20000080, 0, -1, -1, 0);
+ break;
+ case 4:
+ syscall(__NR_pwritev, -1, 0x20000300, 0, 0);
+ break;
+ case 5:
+ syscall(__NR_ioctl, -1, 0x4c06, -1);
+ break;
+ case 6:
+ res = syscall(__NR_shmget, 0, 0x3000, 0, 0x20ffb000);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 7:
+ syscall(__NR_shmctl, r[3], 0);
+ break;
+ case 8:
+ syscall(__NR_shmctl, r[3], 0);
+ break;
+ }
+}
+
+void execute_one()
+{
+ execute(9);
+ collide = 1;
+ execute(9);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (;;) {
+ loop();
+ }
+}
diff --git a/syzkaller-repros/linux/47327accbf258a249ad43a34e8c15524c4c59d34.c b/syzkaller-repros/linux/47327accbf258a249ad43a34e8c15524c4c59d34.c
new file mode 100644
index 0000000..9de67ff
--- /dev/null
+++ b/syzkaller-repros/linux/47327accbf258a249ad43a34e8c15524c4c59d34.c
@@ -0,0 +1,347 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+
+ *(uint8_t*)0x20005100 = 0x12;
+ *(uint8_t*)0x20005101 = 1;
+ *(uint16_t*)0x20005102 = 0;
+ *(uint8_t*)0x20005104 = 0xc7;
+ *(uint8_t*)0x20005105 = 0x40;
+ *(uint8_t*)0x20005106 = 0xb;
+ *(uint8_t*)0x20005107 = 8;
+ *(uint16_t*)0x20005108 = 0xcf3;
+ *(uint16_t*)0x2000510a = 0x9374;
+ *(uint16_t*)0x2000510c = 0xa3f9;
+ *(uint8_t*)0x2000510e = 0;
+ *(uint8_t*)0x2000510f = 0;
+ *(uint8_t*)0x20005110 = 0;
+ *(uint8_t*)0x20005111 = 1;
+ *(uint8_t*)0x20005112 = 9;
+ *(uint8_t*)0x20005113 = 2;
+ *(uint16_t*)0x20005114 = 0x1d;
+ *(uint8_t*)0x20005116 = 1;
+ *(uint8_t*)0x20005117 = 0;
+ *(uint8_t*)0x20005118 = 0;
+ *(uint8_t*)0x20005119 = 0;
+ *(uint8_t*)0x2000511a = 0;
+ *(uint8_t*)0x2000511b = 9;
+ *(uint8_t*)0x2000511c = 4;
+ *(uint8_t*)0x2000511d = 0x2f;
+ *(uint8_t*)0x2000511e = 0;
+ *(uint8_t*)0x2000511f = 1;
+ *(uint8_t*)0x20005120 = 0xaa;
+ *(uint8_t*)0x20005121 = 0x6c;
+ *(uint8_t*)0x20005122 = 0x94;
+ *(uint8_t*)0x20005123 = 0;
+ *(uint8_t*)0x20005124 = 7;
+ *(uint8_t*)0x20005125 = 5;
+ *(uint8_t*)0x20005126 = -1;
+ *(uint8_t*)0x20005127 = 0x10;
+ *(uint16_t*)0x20005128 = 0x401;
+ *(uint8_t*)0x2000512a = 0xdf;
+ *(uint8_t*)0x2000512b = 7;
+ *(uint8_t*)0x2000512c = 1;
+ *(uint8_t*)0x2000512d = 2;
+ *(uint8_t*)0x2000512e = 0x3f;
+ syz_usb_connect(3, 0x2f, 0x20005100, 0);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/492d0d91ed2a9cb9ff43f6aace7a2b99a10e6f3f.c b/syzkaller-repros/linux/492d0d91ed2a9cb9ff43f6aace7a2b99a10e6f3f.c
new file mode 100644
index 0000000..a321a37
--- /dev/null
+++ b/syzkaller-repros/linux/492d0d91ed2a9cb9ff43f6aace7a2b99a10e6f3f.c
@@ -0,0 +1,578 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+struct vusb_descriptor {
+ uint8_t req_type;
+ uint8_t desc_type;
+ uint32_t len;
+ char data[0];
+} __attribute__((packed));
+
+struct vusb_descriptors {
+ uint32_t len;
+ struct vusb_descriptor* generic;
+ struct vusb_descriptor* descs[0];
+} __attribute__((packed));
+
+struct vusb_response {
+ uint8_t type;
+ uint8_t req;
+ uint32_t len;
+ char data[0];
+} __attribute__((packed));
+
+struct vusb_responses {
+ uint32_t len;
+ struct vusb_response* generic;
+ struct vusb_response* resps[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_control_io(volatile long a0, volatile long a1,
+ volatile long a2)
+{
+ int fd = a0;
+ struct vusb_descriptors* descs = (struct vusb_descriptors*)a1;
+ struct vusb_responses* resps = (struct vusb_responses*)a2;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ int rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ return -1;
+ uint8_t req = event.ctrl.bRequest;
+ uint8_t req_type = event.ctrl.bRequestType & USB_TYPE_MASK;
+ uint8_t desc_type = event.ctrl.wValue >> 8;
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ if (req == USB_REQ_GET_DESCRIPTOR) {
+ int i;
+ int descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) /
+ sizeof(descs->descs[0]);
+ for (i = 0; i < descs_num; i++) {
+ struct vusb_descriptor* desc = descs->descs[i];
+ if (!desc)
+ continue;
+ if (desc->req_type == req_type && desc->desc_type == desc_type) {
+ response_length = desc->len;
+ if (response_length != 0)
+ response_data = &desc->data[0];
+ goto reply;
+ }
+ }
+ if (descs->generic) {
+ response_data = &descs->generic->data[0];
+ response_length = descs->generic->len;
+ goto reply;
+ }
+ } else {
+ int i;
+ int resps_num = (resps->len - offsetof(struct vusb_responses, resps)) /
+ sizeof(resps->resps[0]);
+ for (i = 0; i < resps_num; i++) {
+ struct vusb_response* resp = resps->resps[i];
+ if (!resp)
+ continue;
+ if (resp->type == req_type && resp->req == req) {
+ response_length = resp->len;
+ if (response_length != 0)
+ response_data = &resp->data[0];
+ goto reply;
+ }
+ }
+ if (resps->generic) {
+ response_data = &resps->generic->data[0];
+ response_length = resps->generic->len;
+ goto reply;
+ }
+ }
+ return -1;
+ struct usb_fuzzer_ep_io_data response;
+
+reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ sleep_ms(200);
+ return 0;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ long res = 0;
+ *(uint8_t*)0x20000000 = 0x12;
+ *(uint8_t*)0x20000001 = 1;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint8_t*)0x20000004 = 0xb0;
+ *(uint8_t*)0x20000005 = 0xf7;
+ *(uint8_t*)0x20000006 = 0x87;
+ *(uint8_t*)0x20000007 = 8;
+ *(uint16_t*)0x20000008 = 0xe41;
+ *(uint16_t*)0x2000000a = 0x4151;
+ *(uint16_t*)0x2000000c = 0x7a8f;
+ *(uint8_t*)0x2000000e = 0;
+ *(uint8_t*)0x2000000f = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 1;
+ *(uint8_t*)0x20000012 = 9;
+ *(uint8_t*)0x20000013 = 2;
+ *(uint16_t*)0x20000014 = 0x12;
+ *(uint8_t*)0x20000016 = 1;
+ *(uint8_t*)0x20000017 = 0;
+ *(uint8_t*)0x20000018 = 0;
+ *(uint8_t*)0x20000019 = 0;
+ *(uint8_t*)0x2000001a = 0;
+ *(uint8_t*)0x2000001b = 9;
+ *(uint8_t*)0x2000001c = 4;
+ *(uint8_t*)0x2000001d = 0;
+ *(uint8_t*)0x2000001e = 2;
+ *(uint8_t*)0x2000001f = 0;
+ *(uint8_t*)0x20000020 = 0xd6;
+ *(uint8_t*)0x20000021 = 0x36;
+ *(uint8_t*)0x20000022 = 0x16;
+ *(uint8_t*)0x20000023 = 0;
+ res = syz_usb_connect(7, 0x24, 0x20000000, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000d00 = 0x54;
+ *(uint64_t*)0x20000d04 = 0;
+ *(uint64_t*)0x20000d0c = 0x20000ac0;
+ *(uint8_t*)0x20000ac0 = 0;
+ *(uint8_t*)0x20000ac1 = 0xb;
+ *(uint32_t*)0x20000ac2 = 0;
+ *(uint64_t*)0x20000d14 = 0;
+ *(uint64_t*)0x20000d1c = 0;
+ *(uint64_t*)0x20000d24 = 0;
+ *(uint64_t*)0x20000d2c = 0;
+ *(uint64_t*)0x20000d34 = 0;
+ *(uint64_t*)0x20000d3c = 0;
+ *(uint64_t*)0x20000d44 = 0;
+ *(uint64_t*)0x20000d4c = 0;
+ syz_usb_control_io(r[0], 0, 0x20000d00);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/4aa455208960a0581de4d07827f871282e55c78b.c b/syzkaller-repros/linux/4aa455208960a0581de4d07827f871282e55c78b.c
new file mode 100644
index 0000000..760eaa2
--- /dev/null
+++ b/syzkaller-repros/linux/4aa455208960a0581de4d07827f871282e55c78b.c
@@ -0,0 +1,384 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 1;
+ *(uint32_t*)0x2000000c = 3;
+ *(uint32_t*)0x20000010 = 0x100;
+ *(uint64_t*)0x20000018 = 0x200003c0;
+ memcpy(
+ (void*)0x200003c0,
+ "\xcb\xb6\x2c\x7c\x7e\x12\x72\x7d\x60\xc5\xdb\x26\x5c\x1d\x8b\x3f\x75\x25"
+ "\x50\xd4\xea\xc7\xaf\xf1\x02\x13\x26\xe1\x5d\xfd\xad\x91\x1d\x57\xa8\x53"
+ "\x41\x4b\x19\x47\x02\xa4\x1a\x75\x60\x56\x8b\xe1\x11\x1d\xac\x9f\xf2\x58"
+ "\x6d\x67\xdc\x8e\xf3\xe9\xd3\x66\x94\xc5\xea\x96\xd8\x98\x5a\x99\x53\xe8"
+ "\x77\x5c\xbf\x7a\xe1\x51\xea\x1f\xd6\x1f\xbc\x2d\x44\xe7\x60\x31\x83\x3d"
+ "\xff\xb4\x47\xc4\x25\xc9\x74\x9c\x7d\xe7\xfb\xe2\xe5\x65\xb4\xa2\x5f\x7b"
+ "\x2a\xc0\x13\x92\xce\x04\xec\x8d\x6d\x21\x0e\x0a\x23\xae\x3a\x5f\xd8\x1c"
+ "\x3c\x89\xc9\x28\x74\x70\x9f\xcd\xd4\xd4\xc3\xff\xe7\xfa\x05\x2a\xc6\x8f"
+ "\xb6\xdf\x7e\x48\x2e\x24\xbe\x6a\xc8\x19\x10\x39\xb4\x34\xaa\x0e\x9f\x97"
+ "\x39\xae\xdf\x30\xc0\xfa\x9c\x42\xcd\xa4\x11\x02\x5c\xa2\x0c\x42\xbf\x88"
+ "\x68\x56\x03\x99\x87\x3f\x4d\x1b\x28\xed\x71\x3e\x41\x1b\x34\xec\x02\x63"
+ "\x21\xc8\xcd\x9a\xd1\x7c\xbc\x95\x70\x4c\x14\x2d\x7c\x71\x06\x3b\x4a\x0b"
+ "\x52\xe2\x20\x73\xf8\x59\xd6\x32\x89\x92\x12\x6e\x5f\x50\x57\xad\x1d\x02"
+ "\x29\xba\xde\xc1\xe0\x88\x0f\x47\x6f\x18\xce\x68\x55\x60\x78\xa0\x06\x7d"
+ "\x8e\x90\x05\x7f\x56\x0b\x51\x51\xc4\x50\xe6\x55\x89\x81\x2f\x77\x9b\x50"
+ "\xe4\xde\xd6\x60\xee\x4a\xa6\x1e\x7f\x84\xa9\xb4\xb7\x91\x83\x71\x14\x09"
+ "\x55\x39\xfb\x55\x73\xe4\x7c\xce\x26\xdc\x38\x31\x19\x13\x99\x51\x81\xe7"
+ "\x28\xfd\x4d\x6d\x33\x4e\x62\xfd\x0a\x82\x2f\x93\x71\xbc\xdc\x43\xc8\xa6"
+ "\x96\x88\xa1\x1f\xc9\xf4\x3a\xfe\x64\x2c\x30\xdd\xf3\x94\x65\xb1\x3c\xf1"
+ "\xdd\xad\xd7\x89\x70\x77\x18\x27\xf4\x45\xf0\xd4\x56\x1e\x8e\x2b\xb6\xcf"
+ "\x22\x44\x63\x4b\xcd\x72\xd1\x24\xf3\xca\xa1\x52\xc6\xfd\x6d\x47\xbb\x00"
+ "\x4b\x97\x97\x5d\x4a\x46\xb2\xee\x12\x9b\x88\x9d\xc5\x9c\x1c\x71\x62\xff"
+ "\xf2\x2c\x42\x95\x54\x52\x95\xea\x72\xfe\x14\xc6\xb2\xba\xb3\x5a\xb5\x45"
+ "\x51\x73\x98\xb0\x03\xb6\xd3\xb8\x9c\x5c\x64\xb4\x49\xf7\xd5\x60\xdd\xe2"
+ "\x0f\xc1\x3b\x3e\xc8\x8d\xc0\x52\x42\xa1\x60\x07\x6c\xcb\xff\x3e\x32\xb8"
+ "\x78\x0b\xd1\x91\xa0\xb1\x2a\x6f\x99\x00\xa9\x3f\xa1\x2d\x9f\xb5\xed\x34"
+ "\x88\xd5\xcd\x0a\xa3\x29\x58\x3f\x2c\x47\xc4\xfd\x47\x26\x46\x9c\x98\xe0"
+ "\xb6\x6d\x74\xc3\x1d\x0a\x1f\x7f\xc1\x0c\xc1\x94\x4d\x25\x26\x7e\xff\x7a"
+ "\x74\x0c\xc4\x30\x06\x9b\x58\x47\x9c\xa6\x96\x00\x63\x6a\x0f\x22\xa4\x70"
+ "\xa6\x9b\x46\xc1\xcc\x1b\x95\xcf\x32\xdd\x7b\x73\xad\x67\x41\x61\xca\x39"
+ "\x25\x83\xaa\x83\x4a\xaa\xde\x88\xa4\x39\x33\x89\xb7\x6d\x58\x8a\x60\x81"
+ "\x91\xdb\x7c\xa7\x5d\xd0\x09\x38\x2a\x45\x83\xe8\x78\x1e\xb0\x9f\x48\xa4"
+ "\x4d\x06\xb4\x17\x56\xeb\x3f\x1b\x7e\xea\x18\xad\xf2\x97\x83\x22\xd0\xb3"
+ "\x84\xdf\x03\x07\x98\x91\xe1\x0f\x09\x2c\x57\x33\x20\xfb\x94\x1f\x10\xe3"
+ "\xc3\xaf\x6f\x3e\x72\xb2\xaf\xcd\x95\xa3\x66\x6a\x6a\x40\xa8\x40\xe6\x3d"
+ "\x1c\xb9\xe2\x49\x25\xc0\x49\x7a\x04\xef\x7b\x9b\x1e\xe3\x9d\xe0\x45\x6f"
+ "\xec\xd6\x76\xac\xee\x23\x3f\x5b\x64\x5e\x8d\x05\xf3\xf5\x05\xa1\x2a\x0f"
+ "\x5b\x35\x65\x86\xf2\x2c\x2c\x2c\xeb\xef\x83\xc5\xe6\x8c\x22\x72\x34\x95"
+ "\xab\xa0\x64\x27\x92\x55\xde\x48\x9e\x33\xe9\x20\x9a\x63\x68\x90\xbc\xfb"
+ "\x2a\x52\x7e\x8d\xa8\x36\x21\xae\xf3\x74\xf5\xa1\x1d\x8a\xc7\x7f\x5d\xcd"
+ "\x42\x1f\x45\xe5\x2d\xdf\x9b\xc3\x5f\x64\xcf\x72\x1c\xe6\xc9\x6b\x56\x13"
+ "\x26\x8c\x02\x5c\xa9\x91\x0a\x8a\x23\x5e\x6a\xf3\xd6\x7a\xdd\xc6\x6e\x75"
+ "\xc1\x56\x4a\x7f\x86\x84\xfc\xd2\x3e\xc9\x8d\x61\xa4\xfa\x42\x2c\x55\xe6"
+ "\x78\x9c\xbc\x42\xb1\xd5\x32\x63\x3e\x65\x8a\x5c\x2f\xfe\x57\x67\x03\x97"
+ "\x62\xf1\x8c\xce\x89\xb8\x00\x0e\x37\xca\xbc\x35\x40\x9d\x3c\x7a\x02\x13"
+ "\xde\x87\xce\x95\xcf\xbf\xb0\xc7\x1b\xe4\xc4\xef\x44\x86\x6b\xd8\xe0\x50"
+ "\xe3\x36\xb3\x1a\x6e\x8f\x15\xbd\x21\x60\xe5\x48\x48\xad\xa2\x56\xdf\x90"
+ "\x27\x58\xeb\xbc\x1e\x83\x7f\xab\x4c\xb8\xbb\x84\x67\xa7\x3d\xf7\x17\xd9"
+ "\x2e\x22\x04\x48\x2f\xe9\x5c\x21\x12\x11\x86\xa5\x7c\x3b\x12\xf7\x5c\x83"
+ "\x6a\xb7\x02\x43\x34\x18\xf3\x29\x44\x32\x3e\xaa\xad\xbc\xa3\x66\x96\x1c"
+ "\x25\x62\x0c\x43\x95\x1a\x7a\x3f\xd3\xe3\xcc\x85\xd6\xa3\x99\x6b\x50\xd1"
+ "\x2e\xa7\x6d\xf6\x58\xa6\x40\x5f\xdf\x1c\x9f\x2c\x05\x24\x8d\x95\x15\xce"
+ "\x96\x65\x0e\xbf\x62\x96\x64\xe6\xc1\x92\xdd\x28\xe1\x61\x72\xbe\x15\x93"
+ "\xe9\x4d\xbc\xa0\xe5\x54\xfc\xe9\x73\x6c\x73\x54\x03\x0c\x64\xfd\xaf\x35"
+ "\x03\x8e\x1f\x1e\x1d\x20\xe0\x6f\x34\x8e\xf5\xae\x75\x41\x39\xb4\xe8\x12"
+ "\xc6\x0f\xbc\x55\xba\xce\x83\xf2\x7b\xb8\x35\xc1\x64\xc2\x9f\x5f\x7c\x1d"
+ "\xbe\xeb\xfd\x98\x8a\x16\x23\x5c\x4b\xbe\xe4\xd9\xa3\xbc\x66\x6f",
+ 1024);
+ syscall(__NR_ioctl, r[0], 0x4b72ul, 0x20000000ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x20000000 = 0;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint16_t*)0x20000004 = 0x77ff;
+ *(uint16_t*)0x20000006 = 0xb;
+ *(uint16_t*)0x20000008 = 0;
+ *(uint16_t*)0x2000000a = 0;
+ syscall(__NR_ioctl, r[1], 0x560aul, 0x20000000ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[2] = res;
+ *(uint16_t*)0x20000140 = 0x41;
+ *(uint16_t*)0x20000142 = 2;
+ *(uint16_t*)0x20000144 = 7;
+ syscall(__NR_ioctl, r[2], 0x5609ul, 0x20000140ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[3] = res;
+ syscall(__NR_ioctl, r[3], 0x4b3aul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/4ca99bb8684e79c0a748413b46e4a476f35946f3.c b/syzkaller-repros/linux/4ca99bb8684e79c0a748413b46e4a476f35946f3.c
new file mode 100644
index 0000000..1712c74
--- /dev/null
+++ b/syzkaller-repros/linux/4ca99bb8684e79c0a748413b46e4a476f35946f3.c
@@ -0,0 +1,400 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/ndctl0\000", 12);
+ res =
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0x20402ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint64_t*)0x200001c8 = 0x200000c0;
+ *(uint64_t*)0x200001d0 = 0xca;
+ syscall(__NR_ioctl, r[0], 0x4018920aul, 0x200001c0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/4cb6961fc8d91579e9c254fc74dbee8de06b2b43.c b/syzkaller-repros/linux/4cb6961fc8d91579e9c254fc74dbee8de06b2b43.c
new file mode 100644
index 0000000..7a12a96
--- /dev/null
+++ b/syzkaller-repros/linux/4cb6961fc8d91579e9c254fc74dbee8de06b2b43.c
@@ -0,0 +1,423 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_init_net_socket(volatile long domain, volatile long type,
+ volatile long proto)
+{
+ return syscall(__NR_socket, domain, type, proto);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_init_net_socket(0x1a, 2, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x200000c0 = 7;
+ syscall(__NR_setsockopt, r[0], 1ul, 0x3eul, 0x200000c0ul, 4ul);
+ *(uint16_t*)0x20000040 = 0x1a;
+ *(uint16_t*)0x20000042 = 0;
+ *(uint8_t*)0x20000044 = 0;
+ *(uint8_t*)0x20000045 = 0;
+ *(uint8_t*)0x20000046 = 0;
+ *(uint8_t*)0x20000047 = 0;
+ *(uint8_t*)0x20000048 = 0;
+ *(uint8_t*)0x20000049 = 0;
+ *(uint8_t*)0x2000004a = 0;
+ *(uint8_t*)0x2000004b = 0;
+ *(uint8_t*)0x2000004c = 0;
+ *(uint8_t*)0x2000004d = 0;
+ syscall(__NR_bind, r[0], 0x20000040ul, 0x10ul);
+ syscall(__NR_sendmmsg, r[0], 0x20001380ul, 0x3fffffffffffeedul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/4e5cba057fd1e1d7a473942ce22d1981be8a2e68.c b/syzkaller-repros/linux/4e5cba057fd1e1d7a473942ce22d1981be8a2e68.c
new file mode 100644
index 0000000..e00022f
--- /dev/null
+++ b/syzkaller-repros/linux/4e5cba057fd1e1d7a473942ce22d1981be8a2e68.c
@@ -0,0 +1,376 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syz_open_dev(0, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ NONFAILING(memcpy((void*)0x20000080, "/dev/bus/usb/00#/00#\000", 21));
+ syz_open_dev(0x20000080, 0x3404, 0);
+ break;
+ case 2:
+ syscall(__NR_read, r[0], 0, 0xffab);
+ break;
+ case 3:
+ NONFAILING(memcpy((void*)0x208be000, "/dev/usbmon#\000", 13));
+ res = syz_open_dev(0x208be000, 0, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 4:
+ syscall(__NR_mmap, 0x20a05000, 0x400000, 2, 0x200008012, r[1], 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ install_segv_handler();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/4e8f8f42cd1d0965d32183f1805a2c7966e2419b.c b/syzkaller-repros/linux/4e8f8f42cd1d0965d32183f1805a2c7966e2419b.c
new file mode 100644
index 0000000..56ffb6f
--- /dev/null
+++ b/syzkaller-repros/linux/4e8f8f42cd1d0965d32183f1805a2c7966e2419b.c
@@ -0,0 +1,390 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_genetlink_get_family_id(volatile long name)
+{
+ char buf[512] = {0};
+ struct nlmsghdr* hdr = (struct nlmsghdr*)buf;
+ struct genlmsghdr* genlhdr = (struct genlmsghdr*)NLMSG_DATA(hdr);
+ struct nlattr* attr = (struct nlattr*)(genlhdr + 1);
+ hdr->nlmsg_len =
+ sizeof(*hdr) + sizeof(*genlhdr) + sizeof(*attr) + GENL_NAMSIZ;
+ hdr->nlmsg_type = GENL_ID_CTRL;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ genlhdr->cmd = CTRL_CMD_GETFAMILY;
+ attr->nla_type = CTRL_ATTR_FAMILY_NAME;
+ attr->nla_len = sizeof(*attr) + GENL_NAMSIZ;
+ strncpy((char*)(attr + 1), (char*)name, GENL_NAMSIZ);
+ struct iovec iov = {hdr, hdr->nlmsg_len};
+ struct sockaddr_nl addr = {0};
+ addr.nl_family = AF_NETLINK;
+ int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (fd == -1) {
+ return -1;
+ }
+ struct msghdr msg = {&addr, sizeof(addr), &iov, 1, NULL, 0, 0};
+ if (sendmsg(fd, &msg, 0) == -1) {
+ close(fd);
+ return -1;
+ }
+ ssize_t n = recv(fd, buf, sizeof(buf), 0);
+ close(fd);
+ if (n <= 0) {
+ return -1;
+ }
+ if (hdr->nlmsg_type != GENL_ID_CTRL) {
+ return -1;
+ }
+ for (; (char*)attr < buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID)
+ return *(uint16_t*)(attr + 1);
+ }
+ return -1;
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0x0};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000180, "TIPCv2\000", 7);
+ res = syz_genetlink_get_family_id(0x20000180);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint64_t*)0x20000010 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000100;
+ *(uint32_t*)0x20000100 = 0x6c;
+ *(uint16_t*)0x20000104 = r[1];
+ *(uint16_t*)0x20000106 = 1;
+ *(uint32_t*)0x20000108 = 0;
+ *(uint32_t*)0x2000010c = 0;
+ *(uint8_t*)0x20000110 = 3;
+ *(uint8_t*)0x20000111 = 0;
+ *(uint16_t*)0x20000112 = 0;
+ *(uint16_t*)0x20000114 = 0x58;
+ *(uint16_t*)0x20000116 = 1;
+ *(uint16_t*)0x20000118 = 0x10;
+ *(uint16_t*)0x2000011a = 1;
+ memcpy((void*)0x2000011c, "udp:syz0@", 9);
+ *(uint16_t*)0x20000128 = 0x44;
+ *(uint16_t*)0x2000012a = 4;
+ *(uint16_t*)0x2000012c = 0x20;
+ *(uint16_t*)0x2000012e = 1;
+ *(uint16_t*)0x20000130 = 0xa;
+ *(uint16_t*)0x20000132 = htobe16(0);
+ *(uint32_t*)0x20000134 = htobe32(0);
+ *(uint8_t*)0x20000138 = -1;
+ *(uint8_t*)0x20000139 = 0;
+ *(uint8_t*)0x2000013a = 0;
+ *(uint8_t*)0x2000013b = 0;
+ *(uint8_t*)0x2000013c = 0;
+ *(uint8_t*)0x2000013d = 0;
+ *(uint8_t*)0x2000013e = 0;
+ *(uint8_t*)0x2000013f = 0;
+ *(uint8_t*)0x20000140 = 0;
+ *(uint8_t*)0x20000141 = 0;
+ *(uint8_t*)0x20000142 = 0;
+ *(uint8_t*)0x20000143 = 0;
+ *(uint8_t*)0x20000144 = 0;
+ *(uint8_t*)0x20000145 = 0;
+ *(uint8_t*)0x20000146 = 0;
+ *(uint8_t*)0x20000147 = 1;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint16_t*)0x2000014c = 0x20;
+ *(uint16_t*)0x2000014e = 2;
+ *(uint16_t*)0x20000150 = 0xa;
+ *(uint16_t*)0x20000152 = htobe16(0);
+ *(uint32_t*)0x20000154 = htobe32(0);
+ *(uint8_t*)0x20000158 = -1;
+ *(uint8_t*)0x20000159 = 2;
+ *(uint8_t*)0x2000015a = 0;
+ *(uint8_t*)0x2000015b = 0;
+ *(uint8_t*)0x2000015c = 0;
+ *(uint8_t*)0x2000015d = 0;
+ *(uint8_t*)0x2000015e = 0;
+ *(uint8_t*)0x2000015f = 0;
+ *(uint8_t*)0x20000160 = 0;
+ *(uint8_t*)0x20000161 = 0;
+ *(uint8_t*)0x20000162 = 0;
+ *(uint8_t*)0x20000163 = 0;
+ *(uint8_t*)0x20000164 = 0;
+ *(uint8_t*)0x20000165 = 0;
+ *(uint8_t*)0x20000166 = 0;
+ *(uint8_t*)0x20000167 = 1;
+ *(uint32_t*)0x20000168 = 0;
+ *(uint64_t*)0x200000c8 = 0x6c;
+ *(uint64_t*)0x20000018 = 1;
+ *(uint64_t*)0x20000020 = 0;
+ *(uint64_t*)0x20000028 = 0;
+ *(uint32_t*)0x20000030 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000000ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/4f9d538745b5c309ed92a48a40bd62b3a80bfe31.c b/syzkaller-repros/linux/4f9d538745b5c309ed92a48a40bd62b3a80bfe31.c
new file mode 100644
index 0000000..fa61211
--- /dev/null
+++ b/syzkaller-repros/linux/4f9d538745b5c309ed92a48a40bd62b3a80bfe31.c
@@ -0,0 +1,317 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 0x14);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x20000000 = 2;
+ *(uint8_t*)0x20000001 = 2;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint16_t*)0x20000004 = 0;
+ *(uint16_t*)0x20000006 = 0;
+ *(uint16_t*)0x20000008 = 0;
+ *(uint16_t*)0x2000000a = 0;
+ syscall(__NR_ioctl, r[0], 0x541cul, 0x20000000ul);
+ res = syz_open_dev(0xc, 4, 0x14);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000100,
+ "\x82\xaf\xa5\x1d\x23\x73\x58\x78\x3c\xd2\x55\x7c\x70\xa9\x3d\xf1\xbd"
+ "\xf3\x7b\x3d\x42\x89\xe8\x85\xa1\xe9\xf2\x54\x4b\x74\x17\x96\xf4\xdb"
+ "\xc9\x81\xec\x3d\x8e\xf5\x96\x02\x52\x2d\xf4\xdc\x34\xa4\x48\xd5\x19"
+ "\x5a\x10\x61\xba\xdd\x08\xfd\xd0\x53\x78\xb7\x92\x9a\x3b\xcf\xd8\x82"
+ "\x71\x15\xd3\x20\xaf\x9b\x81\xe8\xc8\x18\xcb\x85\x63\x59\xbe\x8b\xca"
+ "\x3e\x52\x1e\x41\x6e\x66\x8c\xd3\xdb\x43\x8a\x44\xe9\x98\x8e\x51\xac"
+ "\x2e\xdc\x3d\xe3\x4d\xbc\x15\x29\xc6\x94\x10\x10\x95\x93\x94\x49\x28"
+ "\x3d\xe5\xf5\x8e\x07\x9c\xd6\xd8\x84\xb8\x82\x66\x32\x41",
+ 133);
+ syscall(__NR_ioctl, r[1], 0x4b61ul, 0x20000100ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5286578726824217cc57e8b812bccf039c3ea341.c b/syzkaller-repros/linux/5286578726824217cc57e8b812bccf039c3ea341.c
new file mode 100644
index 0000000..e905d60
--- /dev/null
+++ b/syzkaller-repros/linux/5286578726824217cc57e8b812bccf039c3ea341.c
@@ -0,0 +1,136 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000340;
+ *(uint32_t*)0x20000340 = 0x6c;
+ *(uint8_t*)0x20000344 = 2;
+ *(uint8_t*)0x20000345 = 6;
+ *(uint16_t*)0x20000346 = 1;
+ *(uint32_t*)0x20000348 = 0;
+ *(uint32_t*)0x2000034c = 0;
+ *(uint8_t*)0x20000350 = 0;
+ *(uint8_t*)0x20000351 = 0;
+ *(uint16_t*)0x20000352 = htobe16(0);
+ *(uint16_t*)0x20000354 = 0xe;
+ *(uint16_t*)0x20000356 = 3;
+ memcpy((void*)0x20000358, "bitmap:ip\000", 10);
+ *(uint16_t*)0x20000364 = 9;
+ *(uint16_t*)0x20000366 = 2;
+ memcpy((void*)0x20000368, "syz1\000", 5);
+ *(uint16_t*)0x20000370 = 0x24;
+ STORE_BY_BITMASK(uint16_t, , 0x20000372, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000373, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000373, 1, 7, 1);
+ *(uint16_t*)0x20000374 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000376, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000377, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000377, 1, 7, 1);
+ *(uint16_t*)0x20000378 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000037a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000037b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000037b, 0, 7, 1);
+ *(uint32_t*)0x2000037c = htobe32(0);
+ *(uint16_t*)0x20000380 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000382, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000383, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000383, 1, 7, 1);
+ *(uint16_t*)0x20000384 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000386, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000387, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000387, 0, 7, 1);
+ *(uint8_t*)0x20000388 = 0xac;
+ *(uint8_t*)0x20000389 = 0x1e;
+ *(uint8_t*)0x2000038a = 0;
+ *(uint8_t*)0x2000038b = 1;
+ *(uint16_t*)0x2000038c = 5;
+ *(uint16_t*)0x2000038e = 0x14;
+ *(uint8_t*)0x20000390 = 1;
+ *(uint16_t*)0x20000394 = 5;
+ *(uint16_t*)0x20000396 = 1;
+ *(uint8_t*)0x20000398 = 7;
+ *(uint16_t*)0x2000039c = 5;
+ *(uint16_t*)0x2000039e = 4;
+ *(uint8_t*)0x200003a0 = 0;
+ *(uint16_t*)0x200003a4 = 5;
+ *(uint16_t*)0x200003a6 = 5;
+ *(uint8_t*)0x200003a8 = 2;
+ *(uint64_t*)0x200002c8 = 0x6c;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000380 = 0;
+ *(uint32_t*)0x20000388 = 0;
+ *(uint64_t*)0x20000390 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000240;
+ *(uint32_t*)0x20000240 = 0x38;
+ *(uint8_t*)0x20000244 = 9;
+ *(uint8_t*)0x20000245 = 6;
+ *(uint16_t*)0x20000246 = 0x8899;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint32_t*)0x2000024c = 0;
+ *(uint8_t*)0x20000250 = 0;
+ *(uint8_t*)0x20000251 = 0;
+ *(uint16_t*)0x20000252 = htobe16(0);
+ *(uint16_t*)0x20000254 = 5;
+ *(uint16_t*)0x20000256 = 1;
+ *(uint8_t*)0x20000258 = 7;
+ *(uint16_t*)0x2000025c = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x2000025e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000025f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000025f, 1, 7, 1);
+ *(uint16_t*)0x20000260 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000262, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000263, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000263, 1, 7, 1);
+ *(uint16_t*)0x20000264 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000266, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000267, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000267, 0, 7, 1);
+ *(uint8_t*)0x20000268 = 0xac;
+ *(uint8_t*)0x20000269 = 0x14;
+ *(uint8_t*)0x2000026a = 0x14;
+ *(uint8_t*)0x2000026b = 0xaa;
+ *(uint16_t*)0x2000026c = 9;
+ *(uint16_t*)0x2000026e = 2;
+ memcpy((void*)0x20000270, "syz1\000", 5);
+ *(uint64_t*)0x200002c8 = 0x38;
+ *(uint64_t*)0x20000398 = 1;
+ *(uint64_t*)0x200003a0 = 0;
+ *(uint64_t*)0x200003a8 = 0;
+ *(uint32_t*)0x200003b0 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000380ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/53c79be6b6f985867ecf07544b1b962c401cdffe.c b/syzkaller-repros/linux/53c79be6b6f985867ecf07544b1b962c401cdffe.c
new file mode 100644
index 0000000..431b497
--- /dev/null
+++ b/syzkaller-repros/linux/53c79be6b6f985867ecf07544b1b962c401cdffe.c
@@ -0,0 +1,294 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000040, "/dev/ttyS3\000", 11);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20001240 = 0x55;
+ *(uint32_t*)0x20001244 = 1;
+ *(uint32_t*)0x20001248 = 0;
+ *(uint32_t*)0x2000124c = 3;
+ *(uint32_t*)0x20001250 = 0xe07;
+ *(uint32_t*)0x20001254 = 4;
+ *(uint32_t*)0x20001258 = 0xc6;
+ *(uint32_t*)0x2000125c = 0x30000000;
+ *(uint32_t*)0x20001260 = 0x7fffffff;
+ *(uint8_t*)0x20001264 = -1;
+ *(uint8_t*)0x20001265 = 6;
+ *(uint32_t*)0x20001268 = 0x1ff;
+ *(uint16_t*)0x2000126c = 6;
+ *(uint16_t*)0x2000126e = 9;
+ *(uint64_t*)0x20001270 = 0;
+ *(uint16_t*)0x20001278 = 0;
+ *(uint32_t*)0x2000127c = 7;
+ *(uint64_t*)0x20001280 = 0x7fff;
+ syscall(__NR_ioctl, r[0], 0x541ful, 0x20001240ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/558c547dbb65dc7e36a85d1c8bce3a9f2097c69e.c b/syzkaller-repros/linux/558c547dbb65dc7e36a85d1c8bce3a9f2097c69e.c
new file mode 100644
index 0000000..99d4bc1
--- /dev/null
+++ b/syzkaller-repros/linux/558c547dbb65dc7e36a85d1c8bce3a9f2097c69e.c
@@ -0,0 +1,609 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 6; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ NONFAILING(memcpy((void*)0x20000100, "/dev/nbd#\000", 10));
+ res = syz_open_dev(0x20000100, 0 + procid * 1, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ res = syz_open_dev(0, 0 + procid * 1, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ res = syscall(__NR_socketpair, 1ul, 1ul, 0ul, 0x20000340ul);
+ if (res != -1)
+ NONFAILING(r[2] = *(uint32_t*)0x20000340);
+ break;
+ case 3:
+ syscall(__NR_ioctl, r[1], 0xab00ul, r[2]);
+ break;
+ case 4:
+ syscall(__NR_ioctl, r[0], 0xab03ul, 0);
+ break;
+ case 5:
+ syscall(__NR_ioctl, -1, 0x125eul, -1);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/55d85e550e13f4a5e3bbe6ca60b6d4c7c448b113.c b/syzkaller-repros/linux/55d85e550e13f4a5e3bbe6ca60b6d4c7c448b113.c
new file mode 100644
index 0000000..2a88fad
--- /dev/null
+++ b/syzkaller-repros/linux/55d85e550e13f4a5e3bbe6ca60b6d4c7c448b113.c
@@ -0,0 +1,234 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+__attribute__((noreturn)) static void doexit(int status)
+{
+ volatile unsigned i;
+ syscall(__NR_exit_group, status);
+ for (i = 0;; i++) {
+ }
+}
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+const int kFailStatus = 67;
+const int kRetryStatus = 69;
+
+static void fail(const char* msg, ...)
+{
+ int e = errno;
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, " (errno %d)\n", e);
+ doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
+}
+
+static uintptr_t syz_open_procfs(uintptr_t a0, uintptr_t a1)
+{
+
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ if (a0 == 0) {
+ snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1);
+ } else if (a0 == (uintptr_t)-1) {
+ snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1);
+ } else {
+ snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0, (char*)a1);
+ }
+ int fd = open(buf, O_RDWR);
+ if (fd == -1)
+ fd = open(buf, O_RDONLY);
+ return fd;
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = 160 << 20;
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 8 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid < 0)
+ fail("sandbox fork failed");
+ if (pid)
+ return pid;
+
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ doexit(1);
+}
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0x0, 0xffffffffffffffff};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_fcntl, -1, 0, 0xffffff9c);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ res = syscall(__NR_ioctl, r[0], 0x8903, 0x20000000);
+ if (res != -1)
+ r[1] = *(uint32_t*)0x20000000;
+ break;
+ case 2:
+ memcpy((void*)0x20000040, "mounts", 7);
+ res = syz_open_procfs(r[1], 0x20000040);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 3:
+ syscall(__NR_ioctl, r[0], 0x541d);
+ break;
+ case 4:
+ *(uint32_t*)0x20000c80 = 2;
+ syscall(__NR_setsockopt, -1, 0x29, 1, 0x20000c80, 4);
+ break;
+ case 5:
+ *(uint64_t*)0x20000240 = 0x20000080;
+ *(uint64_t*)0x20000248 = 0x5e;
+ *(uint64_t*)0x20000250 = 0x20000100;
+ *(uint64_t*)0x20000258 = 0x25;
+ *(uint64_t*)0x20000260 = 0x20000140;
+ *(uint64_t*)0x20000268 = 0x50;
+ *(uint64_t*)0x20000270 = 0x200001c0;
+ *(uint64_t*)0x20000278 = 0x2b;
+ *(uint64_t*)0x20000280 = 0x20000200;
+ *(uint64_t*)0x20000288 = 0x2b;
+ syscall(__NR_preadv, r[2], 0x20000240, 5, 0);
+ break;
+ }
+}
+
+void loop()
+{
+ execute(6);
+ collide = 1;
+ execute(6);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ int pid = do_sandbox_none();
+ int status = 0;
+ while (waitpid(pid, &status, __WALL) != pid) {
+ }
+ return 0;
+}
diff --git a/syzkaller-repros/linux/564641b9ae25ac2c7a9a851e8ae5a80c43c2cf9d.c b/syzkaller-repros/linux/564641b9ae25ac2c7a9a851e8ae5a80c43c2cf9d.c
new file mode 100644
index 0000000..9bff953
--- /dev/null
+++ b/syzkaller-repros/linux/564641b9ae25ac2c7a9a851e8ae5a80c43c2cf9d.c
@@ -0,0 +1,935 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_socketpair, 0x1eul, 1ul, 0, 0x20000140ul);
+ syscall(__NR_socket, 2ul, 2ul, 0ul);
+ syscall(__NR_openat, 0xffffff9c, 0ul, 0x26e1ul, 0ul);
+ syscall(__NR_socket, 0xaul, 6ul, 0ul);
+ syscall(__NR_socket, 0x2bul, 1ul, 0ul);
+ syscall(__NR_socket, 2ul, 0x80001ul, 0x84);
+ syscall(__NR_socket, 0x10ul, 0x800000000080003ul, 0);
+ syscall(__NR_socket, 0xaul, 1ul, 0);
+ syscall(__NR_socket, 0xaul, 1ul, 0);
+ memcpy((void*)0x200000c0, "memory.events\000", 14);
+ syscall(__NR_openat, 0xffffff9c, 0x200000c0ul, 0x26e1ul, 0ul);
+ memcpy((void*)0x20000540, "memory.events\000", 14);
+ syscall(__NR_openat, 0xffffff9c, 0x20000540ul, 0xb00000000065808ul, 0ul);
+ memcpy((void*)0x20000000, "memory.events\000", 14);
+ syscall(__NR_openat, 0xffffff9c, 0x20000000ul, 0x7a05ul, 0x1700ul);
+ syscall(__NR_socket, 0xaul, 0x801ul, 0x84);
+ syscall(__NR_socket, 0xaul, 1ul, 0x84ul);
+ syscall(__NR_socket, 0xaul, 0x10000000005ul, 0x84ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ memcpy((void*)0x20000080, "cgroup.controllers\000", 19);
+ syscall(__NR_openat, 0xffffff9c, 0x20000080ul, 0x275aul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ memcpy((void*)0x20000080, "cgroup.controllers\000", 19);
+ syscall(__NR_openat, 0xffffff9c, 0x20000080ul, 0x275aul, 0ul);
+ res = syscall(__NR_socket, 0xaul, 0x801ul, 0x84);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20004cc0 = 2;
+ *(uint16_t*)0x20004cc2 = htobe16(0);
+ *(uint8_t*)0x20004cc4 = 0xac;
+ *(uint8_t*)0x20004cc5 = 0x14;
+ *(uint8_t*)0x20004cc6 = -1;
+ *(uint8_t*)0x20004cc7 = 0xbb;
+ syscall(__NR_connect, r[0], 0x20004cc0ul, 0x10ul);
+ syscall(__NR_listen, r[0], 8);
+ syscall(__NR_accept4, r[0], 0ul, 0ul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ syscall(__NR_socketpair, 1ul, 2ul, 0ul, 0x20000040ul);
+ syscall(__NR_socket, 0xaul, 1ul, 0);
+ memcpy((void*)0x20000540, "memory.events\000", 14);
+ syscall(__NR_openat, 0xffffff9c, 0x20000540ul, 0xb00000000065808ul, 0ul);
+ memcpy((void*)0x20000000, "memory.events\000", 14);
+ syscall(__NR_openat, 0xffffff9c, 0x20000000ul, 0x7a05ul, 0x1700ul);
+ syscall(__NR_socket, 0xaul, 0x801ul, 0x84);
+ syscall(__NR_socket, 0xaul, 1ul, 0x84ul);
+ syscall(__NR_socket, 0xaul, 0x10000000005ul, 0x84ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ memcpy((void*)0x20000080, "cgroup.controllers\000", 19);
+ syscall(__NR_openat, 0xffffff9c, 0x20000080ul, 0x275aul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ memcpy((void*)0x20000080, "cgroup.controllers\000", 19);
+ syscall(__NR_openat, 0xffffff9c, 0x20000080ul, 0x275aul, 0ul);
+ res = syscall(__NR_socket, 0xaul, 0x801ul, 0x84);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x20004cc0 = 2;
+ *(uint16_t*)0x20004cc2 = htobe16(0);
+ *(uint8_t*)0x20004cc4 = 0xac;
+ *(uint8_t*)0x20004cc5 = 0x14;
+ *(uint8_t*)0x20004cc6 = -1;
+ *(uint8_t*)0x20004cc7 = 0xbb;
+ syscall(__NR_connect, r[1], 0x20004cc0ul, 0x10ul);
+ syscall(__NR_listen, r[1], 8);
+ syscall(__NR_accept4, r[1], 0ul, 0ul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ syscall(__NR_socket, 1ul, 2ul, 0ul);
+ syscall(__NR_socketpair, 1ul, 2ul, 0ul, 0x20000040ul);
+ syscall(__NR_socket, 2ul, 1ul, 0ul);
+ syscall(__NR_socketpair, 0x1eul, 0ul, 0ul, 0x20000000ul);
+ res = syscall(__NR_socket, 0x11ul, 2ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ *(uint32_t*)0x20000080 = -1;
+ syscall(__NR_setsockopt, r[2], 0x107ul, 0x14ul, 0x20000080ul, 4ul);
+ *(uint64_t*)0x20007780 = 0x20000000;
+ *(uint16_t*)0x20000000 = 0x25;
+ *(uint8_t*)0x20000002 = 2;
+ *(uint32_t*)0x20007788 = 0x80;
+ *(uint64_t*)0x20007790 = 0;
+ *(uint64_t*)0x20007798 = 0;
+ *(uint64_t*)0x200077a0 = 0;
+ *(uint64_t*)0x200077a8 = 0;
+ *(uint32_t*)0x200077b0 = 0;
+ syscall(__NR_sendmsg, r[2], 0x20007780ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/565bdd2c27a6fc76117fac4671e984f39cb886f7.c b/syzkaller-repros/linux/565bdd2c27a6fc76117fac4671e984f39cb886f7.c
new file mode 100644
index 0000000..727ea6b
--- /dev/null
+++ b/syzkaller-repros/linux/565bdd2c27a6fc76117fac4671e984f39cb886f7.c
@@ -0,0 +1,316 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000840, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000840ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000340 = 3;
+ *(uint32_t*)0x20000344 = 0;
+ *(uint32_t*)0x20000348 = 0;
+ *(uint32_t*)0x2000034c = 0x8000000;
+ *(uint32_t*)0x20000350 = 0;
+ *(uint32_t*)0x20000354 = 0;
+ *(uint32_t*)0x20000358 = 8;
+ *(uint32_t*)0x2000035c = 0;
+ *(uint32_t*)0x20000360 = 7;
+ *(uint32_t*)0x20000364 = 0;
+ *(uint32_t*)0x20000368 = 0;
+ *(uint32_t*)0x2000036c = 0;
+ *(uint32_t*)0x20000370 = 0;
+ *(uint32_t*)0x20000374 = 0;
+ *(uint32_t*)0x20000378 = 0;
+ *(uint32_t*)0x2000037c = 0;
+ *(uint32_t*)0x20000380 = 0;
+ *(uint32_t*)0x20000384 = 0;
+ *(uint32_t*)0x20000388 = 0;
+ *(uint32_t*)0x2000038c = 0;
+ *(uint32_t*)0x20000390 = 7;
+ *(uint32_t*)0x20000394 = 0;
+ *(uint32_t*)0x20000398 = 3;
+ *(uint32_t*)0x2000039c = 0xfffffffe;
+ *(uint32_t*)0x200003a0 = 0;
+ *(uint32_t*)0x200003a4 = 0;
+ *(uint32_t*)0x200003a8 = 0;
+ *(uint32_t*)0x200003ac = 0;
+ *(uint32_t*)0x200003b0 = 0;
+ *(uint32_t*)0x200003b4 = 0x1f;
+ *(uint32_t*)0x200003b8 = 2;
+ *(uint32_t*)0x200003bc = 3;
+ *(uint32_t*)0x200003c0 = 5;
+ *(uint32_t*)0x200003c4 = 0;
+ *(uint32_t*)0x200003c8 = 4;
+ *(uint32_t*)0x200003cc = 3;
+ *(uint32_t*)0x200003d0 = 0;
+ *(uint32_t*)0x200003d4 = 0;
+ *(uint32_t*)0x200003d8 = 0;
+ *(uint32_t*)0x200003dc = 0;
+ syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000340ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/56edf911a2fb841c33f8eb962efb2c5c2f45514d.c b/syzkaller-repros/linux/56edf911a2fb841c33f8eb962efb2c5c2f45514d.c
new file mode 100644
index 0000000..63abe0e
--- /dev/null
+++ b/syzkaller-repros/linux/56edf911a2fb841c33f8eb962efb2c5c2f45514d.c
@@ -0,0 +1,48 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static void execute_one();
+extern unsigned long long procid;
+
+void loop()
+{
+ while (1) {
+ execute_one();
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+void execute_one()
+{
+ long res = 0;
+ syscall(__NR_socket, 0xa, 0, 0);
+ memcpy((void*)0x20000700, "./bus", 6);
+ res = syscall(__NR_creat, 0x20000700, 8);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000180,
+ "\xf8\x58\x08\x2d\xc1\x6d\x37\x80\x09\x00\x00\x00\x00\x00\x00\x00\x09"
+ "\x9f\x86\x18\x1d\x03\xa3\xf3\x52\xa3",
+ 26);
+ syscall(__NR_write, r[0], 0x20000180, 0x1a);
+ memcpy((void*)0x20000000, "./bus", 6);
+ res = syscall(__NR_open, 0x20000000, 0, 0);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20d83ff8 = 0;
+ syscall(__NR_sendfile, r[0], r[1], 0x20d83ff8, 0x800100000000);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (;;) {
+ loop();
+ }
+}
diff --git a/syzkaller-repros/linux/57f0d245a292ce33a1f0abd020f297e8601ecf21.c b/syzkaller-repros/linux/57f0d245a292ce33a1f0abd020f297e8601ecf21.c
new file mode 100644
index 0000000..5df5b16
--- /dev/null
+++ b/syzkaller-repros/linux/57f0d245a292ce33a1f0abd020f297e8601ecf21.c
@@ -0,0 +1,612 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syz_open_dev(0, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_ioctl, r[0], 0x702ul, 0ul);
+ break;
+ case 2:
+ NONFAILING(memcpy((void*)0x20000240, "/dev/i2c-#\000", 11));
+ res = syz_open_dev(0x20000240, 0, 0x800);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ NONFAILING(*(uint8_t*)0x20000140 = 1);
+ NONFAILING(*(uint8_t*)0x20000141 = 0);
+ NONFAILING(*(uint32_t*)0x20000144 = 6);
+ NONFAILING(*(uint64_t*)0x20000148 = 0x20000000);
+ NONFAILING(*(uint8_t*)0x20000000 = 0);
+ NONFAILING(memcpy(
+ (void*)0x20000001,
+ "\x94\x8e\x06\x0b\x65\xfc\xc8\x49\x2b\x12\x91\x71\xce\x2d\x38\x33\x31"
+ "\xf7\x78\xdb\xf7\xd9\x71\x72\x0a\xa5\xc1\x4f\x00\x8e\x3e\xbe\xe6",
+ 33));
+ syscall(__NR_ioctl, r[1], 0x720ul, 0x20000140ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/586245a7ce8d813f1f34ddd58d77bbc56222e67f.c b/syzkaller-repros/linux/586245a7ce8d813f1f34ddd58d77bbc56222e67f.c
new file mode 100644
index 0000000..40e502a
--- /dev/null
+++ b/syzkaller-repros/linux/586245a7ce8d813f1f34ddd58d77bbc56222e67f.c
@@ -0,0 +1,443 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+#ifndef __NR_sched_setattr
+#define __NR_sched_setattr 314
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_socket, 2ul, 0ul, 0);
+ syscall(__NR_perf_event_open, 0ul, 0, -1ul, -1, 0ul);
+ syscall(__NR_getpid);
+ syscall(__NR_sched_setattr, 0, 0ul, 0ul);
+ syscall(__NR_fchdir, -1);
+ memcpy((void*)0x20000340, "/dev/loop-control\000", 18);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000340ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ inject_fault(32);
+ syscall(__NR_ioctl, r[0], 0x4c80ul, 0ul);
+ syscall(__NR_ioctl, r[0], 0x4c81ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/588bf3cdaa258c756363aaa58b3cc56f08617cae.c b/syzkaller-repros/linux/588bf3cdaa258c756363aaa58b3cc56f08617cae.c
new file mode 100644
index 0000000..25931d5
--- /dev/null
+++ b/syzkaller-repros/linux/588bf3cdaa258c756363aaa58b3cc56f08617cae.c
@@ -0,0 +1,578 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+struct vusb_descriptor {
+ uint8_t req_type;
+ uint8_t desc_type;
+ uint32_t len;
+ char data[0];
+} __attribute__((packed));
+
+struct vusb_descriptors {
+ uint32_t len;
+ struct vusb_descriptor* generic;
+ struct vusb_descriptor* descs[0];
+} __attribute__((packed));
+
+struct vusb_response {
+ uint8_t type;
+ uint8_t req;
+ uint32_t len;
+ char data[0];
+} __attribute__((packed));
+
+struct vusb_responses {
+ uint32_t len;
+ struct vusb_response* generic;
+ struct vusb_response* resps[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_control_io(volatile long a0, volatile long a1,
+ volatile long a2)
+{
+ int fd = a0;
+ struct vusb_descriptors* descs = (struct vusb_descriptors*)a1;
+ struct vusb_responses* resps = (struct vusb_responses*)a2;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ int rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ return -1;
+ uint8_t req = event.ctrl.bRequest;
+ uint8_t req_type = event.ctrl.bRequestType & USB_TYPE_MASK;
+ uint8_t desc_type = event.ctrl.wValue >> 8;
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ if (req == USB_REQ_GET_DESCRIPTOR) {
+ int i;
+ int descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) /
+ sizeof(descs->descs[0]);
+ for (i = 0; i < descs_num; i++) {
+ struct vusb_descriptor* desc = descs->descs[i];
+ if (!desc)
+ continue;
+ if (desc->req_type == req_type && desc->desc_type == desc_type) {
+ response_length = desc->len;
+ if (response_length != 0)
+ response_data = &desc->data[0];
+ goto reply;
+ }
+ }
+ if (descs->generic) {
+ response_data = &descs->generic->data[0];
+ response_length = descs->generic->len;
+ goto reply;
+ }
+ } else {
+ int i;
+ int resps_num = (resps->len - offsetof(struct vusb_responses, resps)) /
+ sizeof(resps->resps[0]);
+ for (i = 0; i < resps_num; i++) {
+ struct vusb_response* resp = resps->resps[i];
+ if (!resp)
+ continue;
+ if (resp->type == req_type && resp->req == req) {
+ response_length = resp->len;
+ if (response_length != 0)
+ response_data = &resp->data[0];
+ goto reply;
+ }
+ }
+ if (resps->generic) {
+ response_data = &resps->generic->data[0];
+ response_length = resps->generic->len;
+ goto reply;
+ }
+ }
+ return -1;
+ struct usb_fuzzer_ep_io_data response;
+
+reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ sleep_ms(200);
+ return 0;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ long res = 0;
+ *(uint8_t*)0x20000000 = 0x12;
+ *(uint8_t*)0x20000001 = 1;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint8_t*)0x20000004 = 0xb0;
+ *(uint8_t*)0x20000005 = 0xf7;
+ *(uint8_t*)0x20000006 = 0x87;
+ *(uint8_t*)0x20000007 = 8;
+ *(uint16_t*)0x20000008 = 0xe41;
+ *(uint16_t*)0x2000000a = 0x4151;
+ *(uint16_t*)0x2000000c = 0x7a8f;
+ *(uint8_t*)0x2000000e = 0;
+ *(uint8_t*)0x2000000f = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 1;
+ *(uint8_t*)0x20000012 = 9;
+ *(uint8_t*)0x20000013 = 2;
+ *(uint16_t*)0x20000014 = 0x12;
+ *(uint8_t*)0x20000016 = 1;
+ *(uint8_t*)0x20000017 = 0;
+ *(uint8_t*)0x20000018 = 0;
+ *(uint8_t*)0x20000019 = 0;
+ *(uint8_t*)0x2000001a = 0;
+ *(uint8_t*)0x2000001b = 9;
+ *(uint8_t*)0x2000001c = 4;
+ *(uint8_t*)0x2000001d = 0;
+ *(uint8_t*)0x2000001e = 2;
+ *(uint8_t*)0x2000001f = 0;
+ *(uint8_t*)0x20000020 = 0xd6;
+ *(uint8_t*)0x20000021 = 0x36;
+ *(uint8_t*)0x20000022 = 0x16;
+ *(uint8_t*)0x20000023 = 0;
+ res = syz_usb_connect(7, 0x24, 0x20000000, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20003e80 = 0x54;
+ *(uint64_t*)0x20003e84 = 0;
+ *(uint64_t*)0x20003e8c = 0x20003c40;
+ *(uint8_t*)0x20003c40 = 0;
+ *(uint8_t*)0x20003c41 = 0xb;
+ *(uint32_t*)0x20003c42 = 0;
+ *(uint64_t*)0x20003e94 = 0;
+ *(uint64_t*)0x20003e9c = 0;
+ *(uint64_t*)0x20003ea4 = 0;
+ *(uint64_t*)0x20003eac = 0;
+ *(uint64_t*)0x20003eb4 = 0;
+ *(uint64_t*)0x20003ebc = 0;
+ *(uint64_t*)0x20003ec4 = 0;
+ *(uint64_t*)0x20003ecc = 0;
+ syz_usb_control_io(r[0], 0, 0x20003e80);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/59ba2f79c97f0c49dfcdf15e4f26aca3b8ffa76e.c b/syzkaller-repros/linux/59ba2f79c97f0c49dfcdf15e4f26aca3b8ffa76e.c
new file mode 100644
index 0000000..0a91de4
--- /dev/null
+++ b/syzkaller-repros/linux/59ba2f79c97f0c49dfcdf15e4f26aca3b8ffa76e.c
@@ -0,0 +1,322 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 0x15);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000000 = 1;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 0x15;
+ *(uint32_t*)0x2000000c = 0x1e;
+ *(uint32_t*)0x20000010 = 0;
+ *(uint64_t*)0x20000018 = 0;
+ syscall(__NR_ioctl, r[0], 0x4b61ul, 0x20000000ul);
+ res = syz_open_dev(0xc, 4, 0x15);
+ if (res != -1)
+ r[1] = res;
+ *(uint32_t*)0x20000440 = 3;
+ *(uint32_t*)0x20000444 = 1;
+ *(uint32_t*)0x20000448 = 0x16;
+ *(uint32_t*)0x2000044c = 0;
+ *(uint32_t*)0x20000450 = 0x35e;
+ *(uint64_t*)0x20000458 = 0;
+ syscall(__NR_ioctl, r[1], 0x4b72ul, 0x20000440ul);
+ res = syz_open_dev(0xc, 4, 0x15);
+ if (res != -1)
+ r[2] = res;
+ *(uint32_t*)0x20000440 = 1;
+ *(uint32_t*)0x20000444 = 0;
+ *(uint32_t*)0x20000448 = 0x16;
+ *(uint32_t*)0x2000044c = 0xe;
+ *(uint32_t*)0x20000450 = 0xa5;
+ *(uint64_t*)0x20000458 = 0x20000040;
+ syscall(__NR_ioctl, r[2], 0x4b72ul, 0x20000440ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5bb058155a1d145f0c26b6a32cd27eeb9950ee11.c b/syzkaller-repros/linux/5bb058155a1d145f0c26b6a32cd27eeb9950ee11.c
new file mode 100644
index 0000000..0838785
--- /dev/null
+++ b/syzkaller-repros/linux/5bb058155a1d145f0c26b6a32cd27eeb9950ee11.c
@@ -0,0 +1,688 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static uintptr_t syz_open_procfs(uintptr_t a0, uintptr_t a1)
+{
+
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ if (a0 == 0) {
+ snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1);
+ } else if (a0 == (uintptr_t)-1) {
+ snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1);
+ } else {
+ snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0, (char*)a1);
+ }
+ int fd = open(buf, O_RDWR);
+ if (fd == -1)
+ fd = open(buf, O_RDONLY);
+ return fd;
+}
+
+static void execute_one();
+extern unsigned long long procid;
+
+void loop()
+{
+ while (1) {
+ execute_one();
+ }
+}
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[13] = {0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0xffffffffffffffff,
+ 0x0,
+ 0x0,
+ 0xffffffffffffffff};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_shmget, 0x798dd814, 0x2000, 0x78000000, 0x20ffe000);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint32_t*)0x20000100 = 0xe8;
+ res = syscall(__NR_getsockopt, -1, 0x29, 0x22, 0x20000000, 0x20000100);
+ if (res != -1) {
+ r[1] = *(uint32_t*)0x20000030;
+ r[2] = *(uint32_t*)0x20000034;
+ }
+ break;
+ case 2:
+ res = syscall(__NR_getresgid, 0x20000140, 0x20000180, 0x200001c0);
+ if (res != -1)
+ r[3] = *(uint32_t*)0x200001c0;
+ break;
+ case 3:
+ *(uint32_t*)0x20000240 = 0xc;
+ res = syscall(__NR_getsockopt, -1, 1, 0x11, 0x20000200, 0x20000240);
+ if (res != -1) {
+ r[4] = *(uint32_t*)0x20000204;
+ r[5] = *(uint32_t*)0x20000208;
+ }
+ break;
+ case 4:
+ memcpy((void*)0x20000280, "./file0", 8);
+ res = syscall(__NR_lstat, 0x20000280, 0x200002c0);
+ if (res != -1)
+ r[6] = *(uint32_t*)0x200002d0;
+ break;
+ case 5:
+ res = syscall(__NR_fcntl, -1, 0x10, 0x20000340);
+ if (res != -1)
+ r[7] = *(uint32_t*)0x20000344;
+ break;
+ case 6:
+ res = syscall(__NR_fcntl, -1, 9);
+ if (res != -1)
+ r[8] = res;
+ break;
+ case 7:
+ *(uint32_t*)0x20000380 = 1;
+ *(uint32_t*)0x20000384 = r[2];
+ *(uint32_t*)0x20000388 = r[3];
+ *(uint32_t*)0x2000038c = r[4];
+ *(uint32_t*)0x20000390 = r[6];
+ *(uint32_t*)0x20000394 = 0x8a;
+ *(uint16_t*)0x20000398 = 0x80;
+ *(uint16_t*)0x2000039a = 0;
+ *(uint64_t*)0x200003a0 = 0;
+ *(uint64_t*)0x200003a8 = 0;
+ *(uint32_t*)0x200003b0 = 0x25e;
+ *(uint64_t*)0x200003b8 = 5;
+ *(uint64_t*)0x200003c0 = 0xfcca;
+ *(uint64_t*)0x200003c8 = 0x3f;
+ *(uint32_t*)0x200003d0 = r[7];
+ *(uint32_t*)0x200003d4 = r[8];
+ *(uint16_t*)0x200003d8 = 1;
+ *(uint16_t*)0x200003da = 0;
+ *(uint64_t*)0x200003e0 = 0;
+ *(uint64_t*)0x200003e8 = 0;
+ syscall(__NR_shmctl, r[0], 1, 0x20000380);
+ break;
+ case 8:
+ memcpy((void*)0x20000400, "net/ip6_tables_matches", 23);
+ res = syz_open_procfs(r[7], 0x20000400);
+ if (res != -1)
+ r[9] = res;
+ break;
+ case 9:
+ syscall(__NR_ioctl, r[9], 0x5607);
+ break;
+ case 10:
+ res = syscall(__NR_semget, 0x798e2635, 3, 4);
+ if (res != -1)
+ r[10] = res;
+ break;
+ case 11:
+ syscall(__NR_fcntl, r[9], 9);
+ break;
+ case 12:
+ memcpy((void*)0x20000440, "system.", 7);
+ memcpy((void*)0x20000447, "system", 7);
+ syscall(__NR_fgetxattr, r[9], 0x20000440, 0x20000480, 0x6c);
+ break;
+ case 13:
+ syscall(__NR_madvise, 0x20ffe000, 0x1000, 0x1b);
+ break;
+ case 14:
+ syscall(__NR_semctl, r[10], 0, 0x13, 0x20000500);
+ break;
+ case 15:
+ *(uint8_t*)0x200005c0 = 2;
+ *(uint16_t*)0x200005c2 = 0;
+ *(uint16_t*)0x200005c4 = 6;
+ *(uint16_t*)0x200005c6 = 0;
+ *(uint16_t*)0x200005c8 = 1;
+ *(uint16_t*)0x200005ca = 1;
+ syscall(__NR_ioctl, r[9], 0x541c, 0x200005c0);
+ break;
+ case 16:
+ syscall(__NR_ioctl, r[9], 0x4b6a, 0x20000600);
+ break;
+ case 17:
+ syscall(__NR_getdents, r[9], 0x200006c0, 0x57);
+ break;
+ case 18:
+ memcpy((void*)0x20000dc0,
+ "\x6e\x61\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000de0 = 0x19;
+ *(uint32_t*)0x20000de4 = 4;
+ *(uint32_t*)0x20000de8 = 0x628;
+ *(uint64_t*)0x20000df0 = 0x20000780;
+ *(uint64_t*)0x20000df8 = 0;
+ *(uint64_t*)0x20000e00 = 0;
+ *(uint64_t*)0x20000e08 = 0x20000950;
+ *(uint64_t*)0x20000e10 = 0x20000bf8;
+ *(uint64_t*)0x20000e18 = 0;
+ *(uint32_t*)0x20000e20 = 0;
+ *(uint64_t*)0x20000e28 = 0x20000740;
+ *(uint64_t*)0x20000e30 = 0x20000780;
+ *(uint32_t*)0x20000780 = 0;
+ memcpy((void*)0x20000784,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x200007a4 = 0;
+ *(uint32_t*)0x200007a8 = 0xfffffffc;
+ *(uint32_t*)0x200007ac = 1;
+ *(uint32_t*)0x200007b0 = 3;
+ *(uint32_t*)0x200007b4 = 9;
+ *(uint16_t*)0x200007b8 = htobe16(0x8864);
+ memcpy((void*)0x200007ba,
+ "\x69\x66\x62\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x200007ca,
+ "\x65\x71\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x200007da,
+ "\x73\x79\x7a\x6b\x61\x6c\x6c\x65\x72\x31\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x200007ea,
+ "\x62\x63\x73\x66\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ *(uint8_t*)0x200007fa = 0xaa;
+ *(uint8_t*)0x200007fb = 0xaa;
+ *(uint8_t*)0x200007fc = 0xaa;
+ *(uint8_t*)0x200007fd = 0xaa;
+ *(uint8_t*)0x200007fe = 0xaa;
+ *(uint8_t*)0x200007ff = 0xbb;
+ *(uint8_t*)0x20000800 = -1;
+ *(uint8_t*)0x20000801 = 0;
+ *(uint8_t*)0x20000802 = 0;
+ *(uint8_t*)0x20000803 = -1;
+ *(uint8_t*)0x20000804 = 0;
+ *(uint8_t*)0x20000805 = 0;
+ *(uint8_t*)0x20000806 = -1;
+ *(uint8_t*)0x20000807 = -1;
+ *(uint8_t*)0x20000808 = -1;
+ *(uint8_t*)0x20000809 = -1;
+ *(uint8_t*)0x2000080a = -1;
+ *(uint8_t*)0x2000080b = -1;
+ *(uint8_t*)0x2000080c = 0;
+ *(uint8_t*)0x2000080d = -1;
+ *(uint8_t*)0x2000080e = -1;
+ *(uint8_t*)0x2000080f = 0;
+ *(uint8_t*)0x20000810 = -1;
+ *(uint8_t*)0x20000811 = -1;
+ *(uint32_t*)0x20000814 = 0xa0;
+ *(uint32_t*)0x20000818 = 0x150;
+ *(uint32_t*)0x2000081c = 0x1a0;
+ memcpy((void*)0x20000820,
+ "\x63\x67\x72\x6f\x75\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000840 = 8;
+ *(uint32_t*)0x20000848 = 8;
+ *(uint32_t*)0x2000084c = 0;
+ memcpy((void*)0x20000850,
+ "\x61\x72\x70\x72\x65\x70\x6c\x79\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000870 = 0x10;
+ *(uint8_t*)0x20000878 = 0xaa;
+ *(uint8_t*)0x20000879 = 0xaa;
+ *(uint8_t*)0x2000087a = 0xaa;
+ *(uint8_t*)0x2000087b = 0xaa;
+ *(uint8_t*)0x2000087c = 0xaa;
+ *(uint8_t*)0x2000087d = 0xbb;
+ *(uint32_t*)0x20000880 = -1;
+ memcpy((void*)0x20000888,
+ "\x6e\x66\x6c\x6f\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x200008a8 = 0x50;
+ *(uint32_t*)0x200008b0 = 8;
+ *(uint16_t*)0x200008b4 = 0;
+ *(uint16_t*)0x200008b6 = 0xde3;
+ *(uint16_t*)0x200008b8 = 0;
+ *(uint16_t*)0x200008ba = 0;
+ memcpy((void*)0x200008bc,
+ "\x08\x45\x6d\xa2\x86\x80\xb5\xeb\xd9\xac\x14\x7f\xaa\x6c\x5c\xe1"
+ "\x17\x67\x74\xb0\xf3\xd0\x85\x8c\x84\x5c\x08\x5a\x18\x69\xe0\xfb"
+ "\xf2\x01\x66\x83\xcd\xe8\x68\xfd\x70\xd4\xc7\xf7\x0d\x9b\xed\x82"
+ "\x85\x02\xdb\xc7\xca\x3f\xdd\xd0\xc6\x63\xfc\xac\xf6\xbf\x02\x66",
+ 64);
+ memcpy((void*)0x20000900,
+ "\x4c\x45\x44\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000920 = 0x28;
+ memcpy((void*)0x20000928,
+ "\x73\x79\x7a\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 27);
+ *(uint8_t*)0x20000943 = 0;
+ *(uint32_t*)0x20000944 = 8;
+ *(uint64_t*)0x20000948 = 0x100000001;
+ *(uint32_t*)0x20000950 = 0;
+ memcpy((void*)0x20000954,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000974 = 1;
+ *(uint32_t*)0x20000978 = -1;
+ *(uint32_t*)0x2000097c = 2;
+ *(uint32_t*)0x20000980 = 9;
+ *(uint32_t*)0x20000984 = 3;
+ *(uint16_t*)0x20000988 = htobe16(0x88e5);
+ memcpy((void*)0x2000098a,
+ "\x74\x65\x61\x6d\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x2000099a,
+ "\x74\x65\x71\x6c\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x200009aa,
+ "\x6c\x6f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x200009ba,
+ "\x74\x75\x6e\x6c\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x200009ca, "\xd8\xa5\x37\x39\xcb\x20", 6);
+ *(uint8_t*)0x200009d0 = -1;
+ *(uint8_t*)0x200009d1 = 0;
+ *(uint8_t*)0x200009d2 = -1;
+ *(uint8_t*)0x200009d3 = -1;
+ *(uint8_t*)0x200009d4 = 0;
+ *(uint8_t*)0x200009d5 = -1;
+ *(uint8_t*)0x200009d6 = 0;
+ *(uint8_t*)0x200009d7 = 0;
+ *(uint8_t*)0x200009d8 = 0;
+ *(uint8_t*)0x200009d9 = 0;
+ *(uint8_t*)0x200009da = 0;
+ *(uint8_t*)0x200009db = 0;
+ *(uint8_t*)0x200009dc = -1;
+ *(uint8_t*)0x200009dd = -1;
+ *(uint8_t*)0x200009de = -1;
+ *(uint8_t*)0x200009df = -1;
+ *(uint8_t*)0x200009e0 = -1;
+ *(uint8_t*)0x200009e1 = -1;
+ *(uint32_t*)0x200009e4 = 0xc0;
+ *(uint32_t*)0x200009e8 = 0xf8;
+ *(uint32_t*)0x200009ec = 0x130;
+ memcpy((void*)0x200009f0,
+ "\x68\x65\x6c\x70\x65\x72\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000a10 = 0x28;
+ *(uint32_t*)0x20000a18 = 0;
+ memcpy((void*)0x20000a1c,
+ "\x51\x2e\x39\x33\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 30);
+ memcpy((void*)0x20000a40,
+ "\x61\x72\x70\x72\x65\x70\x6c\x79\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000a60 = 0x10;
+ *(uint8_t*)0x20000a68 = 0xaa;
+ *(uint8_t*)0x20000a69 = 0xaa;
+ *(uint8_t*)0x20000a6a = 0xaa;
+ *(uint8_t*)0x20000a6b = 0xaa;
+ *(uint8_t*)0x20000a6c = 0xaa;
+ *(uint8_t*)0x20000a6d = 0xa;
+ *(uint32_t*)0x20000a70 = -1;
+ memcpy((void*)0x20000a78,
+ "\x73\x6e\x61\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000a98 = 0x10;
+ *(uint8_t*)0x20000aa0 = 0xaa;
+ *(uint8_t*)0x20000aa1 = 0xaa;
+ *(uint8_t*)0x20000aa2 = 0xaa;
+ *(uint8_t*)0x20000aa3 = 0xaa;
+ *(uint8_t*)0x20000aa4 = 0xaa;
+ *(uint8_t*)0x20000aa5 = 0xaa;
+ *(uint32_t*)0x20000aa8 = 0xfffffffe;
+ *(uint32_t*)0x20000ab0 = 0x19;
+ *(uint32_t*)0x20000ab4 = 0x20;
+ *(uint16_t*)0x20000ab8 = htobe16(0x6003);
+ memcpy((void*)0x20000aba,
+ "\x74\x65\x71\x6c\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x20000aca,
+ "\x73\x69\x74\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x20000ada,
+ "\x74\x65\x71\x6c\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x20000aea,
+ "\x62\x6f\x6e\x64\x5f\x73\x6c\x61\x76\x65\x5f\x30\x00\x00\x00\x00",
+ 16);
+ *(uint8_t*)0x20000afa = 0xaa;
+ *(uint8_t*)0x20000afb = 0xaa;
+ *(uint8_t*)0x20000afc = 0xaa;
+ *(uint8_t*)0x20000afd = 0xaa;
+ *(uint8_t*)0x20000afe = 0xaa;
+ *(uint8_t*)0x20000aff = 0x18;
+ *(uint8_t*)0x20000b00 = -1;
+ *(uint8_t*)0x20000b01 = -1;
+ *(uint8_t*)0x20000b02 = 0;
+ *(uint8_t*)0x20000b03 = -1;
+ *(uint8_t*)0x20000b04 = 0;
+ *(uint8_t*)0x20000b05 = -1;
+ *(uint8_t*)0x20000b06 = 1;
+ *(uint8_t*)0x20000b07 = 0x80;
+ *(uint8_t*)0x20000b08 = 0xc2;
+ *(uint8_t*)0x20000b09 = 0;
+ *(uint8_t*)0x20000b0a = 0;
+ *(uint8_t*)0x20000b0b = 0xe;
+ *(uint8_t*)0x20000b0c = 0;
+ *(uint8_t*)0x20000b0d = 0;
+ *(uint8_t*)0x20000b0e = 0;
+ *(uint8_t*)0x20000b0f = -1;
+ *(uint8_t*)0x20000b10 = -1;
+ *(uint8_t*)0x20000b11 = -1;
+ *(uint32_t*)0x20000b14 = 0x118;
+ *(uint32_t*)0x20000b18 = 0x118;
+ *(uint32_t*)0x20000b1c = 0x148;
+ memcpy((void*)0x20000b20,
+ "\x6d\x61\x63\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000b40 = 0x10;
+ *(uint8_t*)0x20000b48 = 0xaa;
+ *(uint8_t*)0x20000b49 = 0xaa;
+ *(uint8_t*)0x20000b4a = 0xaa;
+ *(uint8_t*)0x20000b4b = 0xaa;
+ *(uint8_t*)0x20000b4c = 0xaa;
+ *(uint8_t*)0x20000b4d = 0xaa;
+ *(uint32_t*)0x20000b50 = 0;
+ memcpy((void*)0x20000b58,
+ "\x72\x61\x74\x65\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000b78 = 0x48;
+ memcpy((void*)0x20000b80,
+ "\x79\x61\x6d\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x20000b90,
+ "\x73\x79\x7a\x6b\x61\x6c\x6c\x65\x72\x31\x00\x00\x00\x00\x00\x00",
+ 16);
+ *(uint16_t*)0x20000ba0 = 4;
+ *(uint16_t*)0x20000ba2 = 2;
+ *(uint32_t*)0x20000ba4 = 8;
+ *(uint32_t*)0x20000ba8 = 0x7ff;
+ *(uint32_t*)0x20000bac = 8;
+ *(uint32_t*)0x20000bb0 = 1;
+ *(uint64_t*)0x20000bb8 = 3;
+ *(uint64_t*)0x20000bc0 = 0x1f;
+ memcpy((void*)0x20000bc8,
+ "\x43\x4c\x41\x53\x53\x49\x46\x59\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000be8 = 8;
+ *(uint32_t*)0x20000bf0 = 0x30000;
+ *(uint32_t*)0x20000bf8 = 0;
+ memcpy((void*)0x20000bfc,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000c1c = 3;
+ *(uint32_t*)0x20000c20 = 0xfffffffc;
+ *(uint32_t*)0x20000c24 = 1;
+ *(uint32_t*)0x20000c28 = 9;
+ *(uint32_t*)0x20000c2c = 0x63;
+ *(uint16_t*)0x20000c30 = htobe16(0x809b);
+ memcpy((void*)0x20000c32,
+ "\x6c\x6f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x20000c42,
+ "\x6c\x6f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ memcpy((void*)0x20000c52, "veth0_to_bridge", 16);
+ memcpy((void*)0x20000c62,
+ "\x76\x6c\x61\x6e\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16);
+ *(uint8_t*)0x20000c72 = 1;
+ *(uint8_t*)0x20000c73 = 0x80;
+ *(uint8_t*)0x20000c74 = 0xc2;
+ *(uint8_t*)0x20000c75 = 0;
+ *(uint8_t*)0x20000c76 = 0;
+ *(uint8_t*)0x20000c77 = 3;
+ *(uint8_t*)0x20000c78 = 0xd3;
+ *(uint8_t*)0x20000c79 = 0;
+ *(uint8_t*)0x20000c7a = 0;
+ *(uint8_t*)0x20000c7b = 0;
+ *(uint8_t*)0x20000c7c = -1;
+ *(uint8_t*)0x20000c7d = -1;
+ *(uint8_t*)0x20000c7e = 1;
+ *(uint8_t*)0x20000c7f = 0x80;
+ *(uint8_t*)0x20000c80 = 0xc2;
+ *(uint8_t*)0x20000c81 = 0;
+ *(uint8_t*)0x20000c82 = 0;
+ *(uint8_t*)0x20000c83 = 3;
+ *(uint8_t*)0x20000c84 = -1;
+ *(uint8_t*)0x20000c85 = -1;
+ *(uint8_t*)0x20000c86 = -1;
+ *(uint8_t*)0x20000c87 = -1;
+ *(uint8_t*)0x20000c88 = 0;
+ *(uint8_t*)0x20000c89 = -1;
+ *(uint32_t*)0x20000c8c = 0x110;
+ *(uint32_t*)0x20000c90 = 0x148;
+ *(uint32_t*)0x20000c94 = 0x180;
+ memcpy((void*)0x20000c98,
+ "\x61\x72\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000cb8 = 0x38;
+ *(uint16_t*)0x20000cc0 = htobe16(0x30b);
+ *(uint16_t*)0x20000cc2 = htobe16(0x88e5);
+ *(uint16_t*)0x20000cc4 = htobe16(0x3149);
+ *(uint8_t*)0x20000cc8 = 0xac;
+ *(uint8_t*)0x20000cc9 = 0x14;
+ *(uint8_t*)0x20000cca = 0x14;
+ *(uint8_t*)0x20000ccb = 0xbb;
+ *(uint32_t*)0x20000ccc = htobe32(-1);
+ *(uint32_t*)0x20000cd0 = htobe32(6);
+ *(uint32_t*)0x20000cd4 = htobe32(0xff000000);
+ *(uint8_t*)0x20000cd8 = 0xaa;
+ *(uint8_t*)0x20000cd9 = 0xaa;
+ *(uint8_t*)0x20000cda = 0xaa;
+ *(uint8_t*)0x20000cdb = 0xaa;
+ *(uint8_t*)0x20000cdc = 0xaa;
+ *(uint8_t*)0x20000cdd = 0x11;
+ *(uint8_t*)0x20000cde = -1;
+ *(uint8_t*)0x20000cdf = 0;
+ *(uint8_t*)0x20000ce0 = -1;
+ *(uint8_t*)0x20000ce1 = 0;
+ *(uint8_t*)0x20000ce2 = -1;
+ *(uint8_t*)0x20000ce3 = 0;
+ memcpy((void*)0x20000ce4, "\xe1\xa7\x46\xbf\xae\xf5", 6);
+ *(uint8_t*)0x20000cea = -1;
+ *(uint8_t*)0x20000ceb = -1;
+ *(uint8_t*)0x20000cec = -1;
+ *(uint8_t*)0x20000ced = -1;
+ *(uint8_t*)0x20000cee = -1;
+ *(uint8_t*)0x20000cef = 0;
+ *(uint8_t*)0x20000cf0 = 0x80;
+ *(uint8_t*)0x20000cf1 = 0x71;
+ memcpy((void*)0x20000cf8,
+ "\x73\x74\x61\x74\x69\x73\x74\x69\x63\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000d18 = 0x18;
+ *(uint16_t*)0x20000d20 = 1;
+ *(uint16_t*)0x20000d22 = 0;
+ *(uint32_t*)0x20000d24 = 1;
+ *(uint32_t*)0x20000d28 = 0xfff;
+ *(uint32_t*)0x20000d2c = 8;
+ *(uint64_t*)0x20000d30 = 7;
+ memcpy((void*)0x20000d38,
+ "\x73\x6e\x61\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000d58 = 0x10;
+ *(uint8_t*)0x20000d60 = -1;
+ *(uint8_t*)0x20000d61 = -1;
+ *(uint8_t*)0x20000d62 = -1;
+ *(uint8_t*)0x20000d63 = -1;
+ *(uint8_t*)0x20000d64 = -1;
+ *(uint8_t*)0x20000d65 = -1;
+ *(uint32_t*)0x20000d68 = 0xfffffffd;
+ memcpy((void*)0x20000d70,
+ "\x73\x6e\x61\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint32_t*)0x20000d90 = 0x10;
+ memcpy((void*)0x20000d98, "\x0d\x2a\x14\xec\x22\x36", 6);
+ *(uint32_t*)0x20000da0 = 0xfffffffd;
+ syscall(__NR_setsockopt, r[9], 0, 0x80, 0x20000dc0, 0x6a0);
+ break;
+ case 19:
+ res = syscall(__NR_getresgid, 0x20000e40, 0x20000e80, 0x20000ec0);
+ if (res != -1)
+ r[11] = *(uint32_t*)0x20000ec0;
+ break;
+ case 20:
+ syscall(__NR_ioctl, r[9], 0x5607);
+ break;
+ case 21:
+ *(uint64_t*)0x20000f00 = 0xa6e0;
+ syscall(__NR_ioctl, r[9], 0x4b63, 0x20000f00);
+ break;
+ case 22:
+ *(uint32_t*)0x20000f40 = r[1];
+ *(uint32_t*)0x20000f44 = htobe32(0xe0000001);
+ *(uint8_t*)0x20000f48 = 0xac;
+ *(uint8_t*)0x20000f49 = 0x14;
+ *(uint8_t*)0x20000f4a = 0x14;
+ *(uint8_t*)0x20000f4b = 0xbb;
+ syscall(__NR_setsockopt, r[9], 0, 8, 0x20000f40, 0xc);
+ break;
+ case 23:
+ memcpy((void*)0x20000f80, "./cgroup/syz1", 14);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000f80, 0x200002, 0);
+ if (res != -1)
+ r[12] = res;
+ break;
+ case 24:
+ syscall(__NR_ioctl, r[9], 0x541b, 0x20000fc0);
+ break;
+ case 25:
+ *(uint32_t*)0x20001000 = r[11];
+ syscall(__NR_setgroups, 1, 0x20001000);
+ break;
+ case 26:
+ syscall(__NR_fcntl, r[12], 0x409, 2);
+ break;
+ case 27:
+ syscall(__NR_semget, 0x798e2635, 3, 0x349);
+ break;
+ case 28:
+ *(uint32_t*)0x20001040 = 3;
+ *(uint32_t*)0x20001044 = r[4];
+ *(uint32_t*)0x20001048 = r[5];
+ *(uint32_t*)0x2000104c = r[4];
+ *(uint32_t*)0x20001050 = r[3];
+ *(uint32_t*)0x20001054 = 0x88;
+ *(uint16_t*)0x20001058 = 0x7fff;
+ *(uint16_t*)0x2000105a = 0;
+ *(uint64_t*)0x20001060 = 0;
+ *(uint64_t*)0x20001068 = 0;
+ *(uint64_t*)0x20001070 = 2;
+ *(uint64_t*)0x20001078 = 0x99;
+ *(uint64_t*)0x20001080 = 0x10001;
+ *(uint64_t*)0x20001088 = 0;
+ *(uint64_t*)0x20001090 = 0;
+ syscall(__NR_semctl, r[10], 0, 1, 0x20001040);
+ break;
+ }
+}
+
+void execute_one()
+{
+ execute(29);
+ collide = 1;
+ execute(29);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (;;) {
+ loop();
+ }
+}
diff --git a/syzkaller-repros/linux/5bb56c5cdf046394533740ed1009789377b7f35a.c b/syzkaller-repros/linux/5bb56c5cdf046394533740ed1009789377b7f35a.c
new file mode 100644
index 0000000..9058e73
--- /dev/null
+++ b/syzkaller-repros/linux/5bb56c5cdf046394533740ed1009789377b7f35a.c
@@ -0,0 +1,31 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+void loop()
+{
+ memcpy((void*)0x20001380, "", 1);
+ *(uint64_t*)0x20001500 = 0x200013c0;
+ memcpy((void*)0x200013c0, "minix", 6);
+ *(uint64_t*)0x20001508 = 0x20001400;
+ memcpy((void*)0x20001400, "ppp1", 5);
+ *(uint64_t*)0x20001510 = 0x20001440;
+ memcpy((void*)0x20001440, "ppp0", 5);
+ *(uint64_t*)0x20001518 = 0x20001480;
+ memcpy((void*)0x20001480, "minix", 6);
+ *(uint64_t*)0x20001520 = 0x200014c0;
+ memcpy((void*)0x200014c0, "ifb0", 5);
+ syscall(__NR_execve, 0x20001380, 0x20001500, 0x20001600);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5c0c25a33eb0651a5b2bdbc944372992dad91a4b.c b/syzkaller-repros/linux/5c0c25a33eb0651a5b2bdbc944372992dad91a4b.c
new file mode 100644
index 0000000..6d70ed5
--- /dev/null
+++ b/syzkaller-repros/linux/5c0c25a33eb0651a5b2bdbc944372992dad91a4b.c
@@ -0,0 +1,742 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x2b, 0x801, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20000040 = 2;
+ *(uint16_t*)0x20000042 = htobe16(0);
+ *(uint32_t*)0x20000044 = htobe32(0);
+ syscall(__NR_connect, r[0], 0x20000040, 0x10);
+ syscall(__NR_sendto, r[0], 0, 0, 0x24040000, 0, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5c4510d56c0a8388beb359182cf651407f669ed8.c b/syzkaller-repros/linux/5c4510d56c0a8388beb359182cf651407f669ed8.c
new file mode 100644
index 0000000..959a6ac
--- /dev/null
+++ b/syzkaller-repros/linux/5c4510d56c0a8388beb359182cf651407f669ed8.c
@@ -0,0 +1,402 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/ndctl0\000", 12);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0x2003ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20000040 = 0xfffa;
+ *(uint16_t*)0x20000042 = 0x1000;
+ *(uint16_t*)0x20000044 = 0x1ff;
+ *(uint16_t*)0x20000046 = 1;
+ *(uint16_t*)0x20000048 = 0;
+ *(uint16_t*)0x2000004a = 5;
+ syscall(__NR_ioctl, r[0], 0x560aul, 0x20000040ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5c7b138065ace9d3f00c0d0fffef2f6854c56a00.c b/syzkaller-repros/linux/5c7b138065ace9d3f00c0d0fffef2f6854c56a00.c
new file mode 100644
index 0000000..50456e8
--- /dev/null
+++ b/syzkaller-repros/linux/5c7b138065ace9d3f00c0d0fffef2f6854c56a00.c
@@ -0,0 +1,1219 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static long syz_open_procfs(volatile long a0, volatile long a1)
+{
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ if (a0 == 0) {
+ NONFAILING(snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1));
+ } else if (a0 == -1) {
+ NONFAILING(snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1));
+ } else {
+ NONFAILING(snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0,
+ (char*)a1));
+ }
+ int fd = open(buf, O_RDWR);
+ if (fd == -1)
+ fd = open(buf, O_RDONLY);
+ return fd;
+}
+
+static long syz_open_pts(volatile long a0, volatile long a1)
+{
+ int ptyno = 0;
+ if (ioctl(a0, TIOCGPTN, &ptyno))
+ return -1;
+ char buf[128];
+ sprintf(buf, "/dev/pts/%d", ptyno);
+ return open(buf, a1, 0);
+}
+
+static long syz_genetlink_get_family_id(volatile long name)
+{
+ char buf[512] = {0};
+ struct nlmsghdr* hdr = (struct nlmsghdr*)buf;
+ struct genlmsghdr* genlhdr = (struct genlmsghdr*)NLMSG_DATA(hdr);
+ struct nlattr* attr = (struct nlattr*)(genlhdr + 1);
+ hdr->nlmsg_len =
+ sizeof(*hdr) + sizeof(*genlhdr) + sizeof(*attr) + GENL_NAMSIZ;
+ hdr->nlmsg_type = GENL_ID_CTRL;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ genlhdr->cmd = CTRL_CMD_GETFAMILY;
+ attr->nla_type = CTRL_ATTR_FAMILY_NAME;
+ attr->nla_len = sizeof(*attr) + GENL_NAMSIZ;
+ NONFAILING(strncpy((char*)(attr + 1), (char*)name, GENL_NAMSIZ));
+ struct iovec iov = {hdr, hdr->nlmsg_len};
+ struct sockaddr_nl addr = {0};
+ addr.nl_family = AF_NETLINK;
+ int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (fd == -1) {
+ return -1;
+ }
+ struct msghdr msg = {&addr, sizeof(addr), &iov, 1, NULL, 0, 0};
+ if (sendmsg(fd, &msg, 0) == -1) {
+ close(fd);
+ return -1;
+ }
+ ssize_t n = recv(fd, buf, sizeof(buf), 0);
+ close(fd);
+ if (n <= 0) {
+ return -1;
+ }
+ if (hdr->nlmsg_type != GENL_ID_CTRL) {
+ return -1;
+ }
+ for (; (char*)attr < buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID)
+ return *(uint16_t*)(attr + 1);
+ }
+ return -1;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 45; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[21] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 4ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ NONFAILING(*(uint64_t*)0x20000040 = 0);
+ NONFAILING(*(uint32_t*)0x20000048 = 0);
+ NONFAILING(*(uint64_t*)0x20000050 = 0);
+ NONFAILING(*(uint64_t*)0x20000058 = 1);
+ NONFAILING(*(uint64_t*)0x20000060 = 0);
+ NONFAILING(*(uint64_t*)0x20000068 = 0);
+ NONFAILING(*(uint32_t*)0x20000070 = 0);
+ syscall(__NR_sendmsg, r[0], 0x20000040ul, 0ul);
+ break;
+ case 2:
+ NONFAILING(memcpy((void*)0x20000600, "/dev/snd/seq\000", 13));
+ res = syz_open_dev(0x20000600, 0, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ NONFAILING(*(uint8_t*)0x20068f50 = 0x80);
+ NONFAILING(*(uint8_t*)0x20068f51 = 0);
+ NONFAILING(
+ memcpy((void*)0x20068f52,
+ "port0\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
+ 64));
+ NONFAILING(*(uint32_t*)0x20068f94 = 0xc3);
+ NONFAILING(*(uint32_t*)0x20068f98 = 0x80003);
+ NONFAILING(*(uint32_t*)0x20068f9c = 0);
+ NONFAILING(*(uint32_t*)0x20068fa0 = 0);
+ NONFAILING(*(uint32_t*)0x20068fa4 = 0);
+ NONFAILING(*(uint32_t*)0x20068fa8 = 0);
+ NONFAILING(*(uint32_t*)0x20068fac = 0);
+ NONFAILING(*(uint64_t*)0x20068fb0 = 0);
+ NONFAILING(*(uint32_t*)0x20068fb8 = 0);
+ NONFAILING(*(uint8_t*)0x20068fbc = 0);
+ NONFAILING(*(uint8_t*)0x20068fbd = 0);
+ NONFAILING(*(uint8_t*)0x20068fbe = 0);
+ NONFAILING(*(uint8_t*)0x20068fbf = 0);
+ NONFAILING(*(uint8_t*)0x20068fc0 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc1 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc2 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc3 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc4 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc5 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc6 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc7 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc8 = 0);
+ NONFAILING(*(uint8_t*)0x20068fc9 = 0);
+ NONFAILING(*(uint8_t*)0x20068fca = 0);
+ NONFAILING(*(uint8_t*)0x20068fcb = 0);
+ NONFAILING(*(uint8_t*)0x20068fcc = 0);
+ NONFAILING(*(uint8_t*)0x20068fcd = 0);
+ NONFAILING(*(uint8_t*)0x20068fce = 0);
+ NONFAILING(*(uint8_t*)0x20068fcf = 0);
+ NONFAILING(*(uint8_t*)0x20068fd0 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd1 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd2 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd3 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd4 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd5 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd6 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd7 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd8 = 0);
+ NONFAILING(*(uint8_t*)0x20068fd9 = 0);
+ NONFAILING(*(uint8_t*)0x20068fda = 0);
+ NONFAILING(*(uint8_t*)0x20068fdb = 0);
+ NONFAILING(*(uint8_t*)0x20068fdc = 0);
+ NONFAILING(*(uint8_t*)0x20068fdd = 0);
+ NONFAILING(*(uint8_t*)0x20068fde = 0);
+ NONFAILING(*(uint8_t*)0x20068fdf = 0);
+ NONFAILING(*(uint8_t*)0x20068fe0 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe1 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe2 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe3 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe4 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe5 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe6 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe7 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe8 = 0);
+ NONFAILING(*(uint8_t*)0x20068fe9 = 0);
+ NONFAILING(*(uint8_t*)0x20068fea = 0);
+ NONFAILING(*(uint8_t*)0x20068feb = 0);
+ NONFAILING(*(uint8_t*)0x20068fec = 0);
+ NONFAILING(*(uint8_t*)0x20068fed = 0);
+ NONFAILING(*(uint8_t*)0x20068fee = 0);
+ NONFAILING(*(uint8_t*)0x20068fef = 0);
+ NONFAILING(*(uint8_t*)0x20068ff0 = 0);
+ NONFAILING(*(uint8_t*)0x20068ff1 = 0);
+ NONFAILING(*(uint8_t*)0x20068ff2 = 0);
+ NONFAILING(*(uint8_t*)0x20068ff3 = 0);
+ NONFAILING(*(uint8_t*)0x20068ff4 = 0);
+ NONFAILING(*(uint8_t*)0x20068ff5 = 0);
+ NONFAILING(*(uint8_t*)0x20068ff6 = 0);
+ NONFAILING(*(uint8_t*)0x20068ff7 = 0);
+ syscall(__NR_ioctl, r[1], 0xc0a85320ul, 0x20068f50ul);
+ break;
+ case 4:
+ syscall(__NR_socket, 0x11ul, 3ul, 0x300ul);
+ break;
+ case 5:
+ NONFAILING(*(uint32_t*)0x2001d000 = 1);
+ NONFAILING(*(uint32_t*)0x2001d004 = 0x70);
+ NONFAILING(*(uint8_t*)0x2001d008 = 0);
+ NONFAILING(*(uint8_t*)0x2001d009 = 0);
+ NONFAILING(*(uint8_t*)0x2001d00a = 0);
+ NONFAILING(*(uint8_t*)0x2001d00b = 0);
+ NONFAILING(*(uint32_t*)0x2001d00c = 0);
+ NONFAILING(*(uint64_t*)0x2001d010 = 0x7f);
+ NONFAILING(*(uint64_t*)0x2001d018 = 0);
+ NONFAILING(*(uint64_t*)0x2001d020 = 0);
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 0, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 1, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 2, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 3, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 4, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0x81, 5, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 6, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 7, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 8, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 9, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 10, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 11, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 12, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 13, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 14, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 15, 2));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 17, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 18, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 19, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 20, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 21, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 22, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 23, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 24, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 25, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 26, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 27, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 28, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 29, 35));
+ NONFAILING(*(uint32_t*)0x2001d030 = 0);
+ NONFAILING(*(uint32_t*)0x2001d034 = 0);
+ NONFAILING(*(uint64_t*)0x2001d038 = 0);
+ NONFAILING(*(uint64_t*)0x2001d040 = 0);
+ NONFAILING(*(uint64_t*)0x2001d048 = 0);
+ NONFAILING(*(uint64_t*)0x2001d050 = 0);
+ NONFAILING(*(uint32_t*)0x2001d058 = 0);
+ NONFAILING(*(uint32_t*)0x2001d05c = 0);
+ NONFAILING(*(uint64_t*)0x2001d060 = 0);
+ NONFAILING(*(uint32_t*)0x2001d068 = 0);
+ NONFAILING(*(uint16_t*)0x2001d06c = 0);
+ NONFAILING(*(uint16_t*)0x2001d06e = 0);
+ syscall(__NR_perf_event_open, 0x2001d000ul, 0, 0ul, -1, 0ul);
+ break;
+ case 6:
+ syz_genetlink_get_family_id(0);
+ break;
+ case 7:
+ NONFAILING(memcpy((void*)0x20000040, "/dev/ptmx\000", 10));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 8:
+ NONFAILING(*(uint32_t*)0x203b9fdc = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe0 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe4 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe8 = 0);
+ NONFAILING(*(uint8_t*)0x203b9fec = 0);
+ NONFAILING(memcpy((void*)0x203b9fed,
+ "\xde\xff\xff\xff\xff\xff\xff\xa7\x00\x00\x00\x00\x00\x00"
+ "\x08\x00\x00\x00\x00",
+ 19));
+ syscall(__NR_ioctl, r[2], 0x40045431ul, 0x203b9fdcul);
+ break;
+ case 9:
+ NONFAILING(memcpy((void*)0x20000180, "net/dev_mcast\000", 14));
+ res = syz_open_procfs(0, 0x20000180);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 10:
+ NONFAILING(memcpy((void*)0x20000040, "/dev/ptmx\000", 10));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 11:
+ syscall(__NR_ioctl, r[4], 0x40045431ul, 0ul);
+ break;
+ case 12:
+ NONFAILING(memcpy((void*)0x20000780,
+ "team0\000\000\000\000\000\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint32_t*)0x20000790 = 0);
+ syscall(__NR_ioctl, r[3], 0x8933ul, 0x20000780ul);
+ break;
+ case 13:
+ NONFAILING(memcpy((void*)0x20000180, "net/dev_mcast\000", 14));
+ res = syz_open_procfs(0, 0x20000180);
+ if (res != -1)
+ r[5] = res;
+ break;
+ case 14:
+ NONFAILING(memcpy((void*)0x20000040, "/dev/ptmx\000", 10));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[6] = res;
+ break;
+ case 15:
+ NONFAILING(*(uint32_t*)0x203b9fdc = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe0 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe4 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe8 = 0);
+ NONFAILING(*(uint8_t*)0x203b9fec = 0);
+ NONFAILING(memcpy((void*)0x203b9fed,
+ "\xde\xff\xff\xff\xff\xff\xff\xa7\x00\x00\x00\x00\x00\x00"
+ "\x08\x00\x00\x00\x00",
+ 19));
+ syscall(__NR_ioctl, r[6], 0x40045431ul, 0x203b9fdcul);
+ break;
+ case 16:
+ res = syz_open_pts(r[6], 0x2a801);
+ if (res != -1)
+ r[7] = res;
+ break;
+ case 17:
+ syscall(__NR_sendfile, r[7], r[5], 0ul, 0x6f0a77bdul);
+ break;
+ case 18:
+ NONFAILING(memcpy((void*)0x20000180, "net/dev_mcast\000", 14));
+ res = syz_open_procfs(0, 0x20000180);
+ if (res != -1)
+ r[8] = res;
+ break;
+ case 19:
+ NONFAILING(memcpy((void*)0x20000040, "/dev/ptmx\000", 10));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[9] = res;
+ break;
+ case 20:
+ NONFAILING(*(uint32_t*)0x203b9fdc = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe0 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe4 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe8 = 0);
+ NONFAILING(*(uint8_t*)0x203b9fec = 0);
+ NONFAILING(memcpy((void*)0x203b9fed,
+ "\xde\xff\xff\xff\xff\xff\xff\xa7\x00\x00\x00\x00\x00\x00"
+ "\x08\x00\x00\x00\x00",
+ 19));
+ syscall(__NR_ioctl, r[9], 0x40045431ul, 0x203b9fdcul);
+ break;
+ case 21:
+ res = syz_open_pts(r[9], 0x2a801);
+ if (res != -1)
+ r[10] = res;
+ break;
+ case 22:
+ syscall(__NR_sendfile, r[10], r[8], 0ul, 0x6f0a77bdul);
+ break;
+ case 23:
+ res = syz_open_procfs(0, 0);
+ if (res != -1)
+ r[11] = res;
+ break;
+ case 24:
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0ul, 0ul);
+ if (res != -1)
+ r[12] = res;
+ break;
+ case 25:
+ NONFAILING(*(uint32_t*)0x203b9fdc = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe0 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe4 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe8 = 0);
+ NONFAILING(*(uint8_t*)0x203b9fec = 0);
+ NONFAILING(memcpy((void*)0x203b9fed,
+ "\xde\xff\xff\xff\xff\xff\xff\xa7\x00\x00\x00\x00\x00\x00"
+ "\x08\x00\x00\x00\x00",
+ 19));
+ syscall(__NR_ioctl, r[12], 0x40045431ul, 0x203b9fdcul);
+ break;
+ case 26:
+ syscall(__NR_sendfile, -1, r[11], 0ul, 0x6f0a77bdul);
+ break;
+ case 27:
+ NONFAILING(*(uint32_t*)0x200008c0 = 0xe8);
+ syscall(__NR_getsockopt, r[11], 0x29ul, 0x22ul, 0x200007c0ul, 0x200008c0ul);
+ break;
+ case 28:
+ NONFAILING(*(uint32_t*)0x20000ac0 = 0xc);
+ syscall(__NR_getsockopt, -1, 0ul, 8ul, 0x20000a80ul, 0x20000ac0ul);
+ break;
+ case 29:
+ NONFAILING(memcpy((void*)0x20000b00,
+ "team0\000\000\000\000\000\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint32_t*)0x20000b10 = 0);
+ syscall(__NR_ioctl, -1, 0x8933ul, 0x20000b00ul);
+ break;
+ case 30:
+ syscall(__NR_recvmsg, -1, 0ul, 2ul);
+ break;
+ case 31:
+ syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ break;
+ case 32:
+ res = syscall(__NR_socketpair, 1ul, 2ul, 0ul, 0x20000100ul);
+ if (res != -1)
+ NONFAILING(r[13] = *(uint32_t*)0x20000104);
+ break;
+ case 33:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[14] = res;
+ break;
+ case 34:
+ NONFAILING(memcpy((void*)0x20000300,
+ "syz_tun\000\000\000\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint32_t*)0x20000310 = 0);
+ res = syscall(__NR_ioctl, r[13], 0x8933ul, 0x20000300ul);
+ if (res != -1)
+ NONFAILING(r[15] = *(uint32_t*)0x20000310);
+ break;
+ case 35:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[16] = res;
+ break;
+ case 36:
+ res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ if (res != -1)
+ r[17] = res;
+ break;
+ case 37:
+ NONFAILING(*(uint64_t*)0x200001c0 = 0);
+ NONFAILING(*(uint32_t*)0x200001c8 = 0);
+ NONFAILING(*(uint64_t*)0x200001d0 = 0x20000180);
+ NONFAILING(*(uint64_t*)0x20000180 = 0);
+ NONFAILING(*(uint64_t*)0x20000188 = 0x3d2);
+ NONFAILING(*(uint64_t*)0x200001d8 = 1);
+ NONFAILING(*(uint64_t*)0x200001e0 = 0);
+ NONFAILING(*(uint64_t*)0x200001e8 = 0);
+ NONFAILING(*(uint32_t*)0x200001f0 = 0);
+ syscall(__NR_sendmsg, r[17], 0x200001c0ul, 0ul);
+ break;
+ case 38:
+ NONFAILING(*(uint32_t*)0x20000200 = 0x14);
+ res = syscall(__NR_getsockname, r[17], 0x20000100ul, 0x20000200ul);
+ if (res != -1)
+ NONFAILING(r[18] = *(uint32_t*)0x20000104);
+ break;
+ case 39:
+ NONFAILING(*(uint64_t*)0x20000180 = 0);
+ NONFAILING(*(uint32_t*)0x20000188 = 0);
+ NONFAILING(*(uint64_t*)0x20000190 = 0x200000c0);
+ NONFAILING(*(uint64_t*)0x200000c0 = 0x20000000);
+ NONFAILING(memcpy((void*)0x20000000,
+ "\x34\x00\x00\x00\x10\x00\x01\x04\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00",
+ 20));
+ NONFAILING(*(uint32_t*)0x20000014 = r[18]);
+ NONFAILING(memcpy((void*)0x20000018,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x12\x00\x0c\x00"
+ "\x01\x00\x62\x72\x69\x64\x67\x65\x00\x00\x00\x02\x00",
+ 27));
+ NONFAILING(*(uint64_t*)0x200000c8 = 0x34);
+ NONFAILING(*(uint64_t*)0x20000198 = 1);
+ NONFAILING(*(uint64_t*)0x200001a0 = 0);
+ NONFAILING(*(uint64_t*)0x200001a8 = 0);
+ NONFAILING(*(uint32_t*)0x200001b0 = 0);
+ syscall(__NR_sendmsg, r[16], 0x20000180ul, 0ul);
+ break;
+ case 40:
+ NONFAILING(*(uint64_t*)0x20000000 = 0);
+ NONFAILING(*(uint32_t*)0x20000008 = 0);
+ NONFAILING(*(uint64_t*)0x20000010 = 0x200000c0);
+ NONFAILING(*(uint64_t*)0x200000c0 = 0x20000400);
+ NONFAILING(memcpy((void*)0x20000400,
+ "\x28\x00\x00\x00\x10\x00\x01\x04\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00",
+ 20));
+ NONFAILING(*(uint32_t*)0x20000414 = r[15]);
+ NONFAILING(memcpy((void*)0x20000418,
+ "\000\000\000\000\000\000\000\000\b\000\n\000", 12));
+ NONFAILING(*(uint32_t*)0x20000424 = r[18]);
+ NONFAILING(memcpy(
+ (void*)0x20000428,
+ "\xa9\x15\xa1\x19\x4c\xc8\x05\xf5\x15\x50\x4c\xa7\xe4\x40\x6f\x03\x6e"
+ "\xae\xc7\x47\xc5\x75\x9f\x47\x85\xa2\x6d\x5c\xe8\x85\x75\x08\xb7\x4f"
+ "\x15\x19\xd4\x71\x25\xbe\x1e\xf3\x2b\xef\x45\xb3\x02\x22\x82\x3c\xe3"
+ "\x39\x6d\x3e\x44\x70\xbf\x5d\xd8\x35\x3d\xec\x62\x70\xac\x50\xa3\x02"
+ "\x62\x5a\x1e\xfc\x46\x06\x91\xf4\xdc\x1b\x39\x64\xbd\xb4\x58\x88\x0e"
+ "\x29\xe4\x04\x1a\xed\xf8\x64\xc7\x25\x80\x6c\xc3\x99\x44\xd5\x34\xe0"
+ "\x45\x56\xf4\x95\x6e\xe9\x49\x93\x88\xde\x81\xe0\x44\xd6\x26\x79\x69"
+ "\x72\x46\x89\x02\xd6\xd8\xc3\xd4\x05\xa6\xa9\x45\x45\xaa\xa3\x27\x3d"
+ "\xc1\x1e\x09\x37\xc2\xa2\xb3\x1c\x9e\x36\xa9\x8f\x14\xf3\x49\xcf\x32"
+ "\x97\x17\xd3\x14\x61",
+ 158));
+ NONFAILING(*(uint64_t*)0x200000c8 = 0x28);
+ NONFAILING(*(uint64_t*)0x20000018 = 1);
+ NONFAILING(*(uint64_t*)0x20000020 = 0);
+ NONFAILING(*(uint64_t*)0x20000028 = 0);
+ NONFAILING(*(uint32_t*)0x20000030 = 0);
+ syscall(__NR_sendmsg, r[14], 0x20000000ul, 0ul);
+ break;
+ case 41:
+ NONFAILING(memcpy((void*)0x20000180, "net/dev_mcast\000", 14));
+ res = syz_open_procfs(0, 0x20000180);
+ if (res != -1)
+ r[19] = res;
+ break;
+ case 42:
+ NONFAILING(memcpy((void*)0x20000040, "/dev/ptmx\000", 10));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[20] = res;
+ break;
+ case 43:
+ NONFAILING(*(uint32_t*)0x203b9fdc = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe0 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe4 = 0);
+ NONFAILING(*(uint32_t*)0x203b9fe8 = 0);
+ NONFAILING(*(uint8_t*)0x203b9fec = 0);
+ NONFAILING(memcpy((void*)0x203b9fed,
+ "\xde\xff\xff\xff\xff\xff\xff\xa7\x00\x00\x00\x00\x00\x00"
+ "\x08\x00\x00\x00\x00",
+ 19));
+ syscall(__NR_ioctl, r[20], 0x40045431ul, 0x203b9fdcul);
+ break;
+ case 44:
+ syscall(__NR_sendfile, -1, r[19], 0ul, 0x6f0a77bdul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5d77610aeaaeddfa55c57a964fb4f4ae7e08c30c.c b/syzkaller-repros/linux/5d77610aeaaeddfa55c57a964fb4f4ae7e08c30c.c
new file mode 100644
index 0000000..a7bfea2
--- /dev/null
+++ b/syzkaller-repros/linux/5d77610aeaaeddfa55c57a964fb4f4ae7e08c30c.c
@@ -0,0 +1,484 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 6; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ *(uint64_t*)0x200000c0 = 0x20000100;
+ *(uint16_t*)0x20000100 = 0xa;
+ *(uint16_t*)0x20000102 = 8;
+ *(uint32_t*)0x20000104 = 0;
+ *(uint32_t*)0x20000108 = 0;
+ *(uint32_t*)0x200000c8 = 0x293;
+ *(uint64_t*)0x200000d0 = 0x20000040;
+ *(uint64_t*)0x20000040 = 0;
+ *(uint64_t*)0x20000048 = 0;
+ *(uint64_t*)0x200000d8 = 1;
+ *(uint64_t*)0x200000e0 = 0;
+ *(uint64_t*)0x200000e8 = 0;
+ *(uint32_t*)0x200000f0 = 0;
+ syscall(__NR_sendmsg, -1, 0x200000c0ul, 0ul);
+ break;
+ case 1:
+ *(uint64_t*)0x20000280 = 0;
+ *(uint32_t*)0x20000288 = 0;
+ *(uint64_t*)0x20000290 = 0x20000240;
+ *(uint64_t*)0x20000240 = 0x20000100;
+ memcpy((void*)0x20000100,
+ "\x14\x00\x00\x00\x10\x00\x00\x00\x00\x6c\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x0a\x20\x00\x00\x00\x00\x0a\x01\x04\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30"
+ "\x00\x00\x00\x00\x38\x00\x00\x00\x12\x0a\x01\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x04\x80\x09\x00\x02\x00"
+ "\x02\xf5\xff\x00\x20\x00\xec\x00\x09\x00\x01\x00\x73\x79\x7a\x30"
+ "\x00\x00\x00\x00\x08\x00\x03",
+ 103);
+ *(uint64_t*)0x20000248 = 1;
+ *(uint64_t*)0x20000298 = 1;
+ *(uint64_t*)0x200002a0 = 0;
+ *(uint64_t*)0x200002a8 = 0;
+ *(uint32_t*)0x200002b0 = 0;
+ syscall(__NR_sendmsg, -1, 0x20000280ul, 0ul);
+ break;
+ case 2:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 3:
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c8 = 0x241;
+ *(uint64_t*)0x200001d0 = 0x20000080;
+ *(uint64_t*)0x20000080 = 0;
+ *(uint64_t*)0x20000088 = 0;
+ *(uint64_t*)0x200001d8 = 8;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001f0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x200001c0ul, 0ul);
+ break;
+ case 4:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 5:
+ *(uint64_t*)0x20000c40 = 0;
+ *(uint32_t*)0x20000c48 = 0;
+ *(uint64_t*)0x20000c50 = 0x20000c00;
+ *(uint64_t*)0x20000c00 = 0x20000180;
+ *(uint32_t*)0x20000180 = 0x14;
+ *(uint16_t*)0x20000184 = 0x10;
+ *(uint16_t*)0x20000186 = 1;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint32_t*)0x2000018c = 0;
+ *(uint8_t*)0x20000190 = 0;
+ *(uint8_t*)0x20000191 = 0;
+ *(uint16_t*)0x20000192 = htobe16(0xa);
+ *(uint32_t*)0x20000194 = 0x14;
+ *(uint8_t*)0x20000198 = 2;
+ *(uint8_t*)0x20000199 = 0xa;
+ *(uint16_t*)0x2000019a = 0xdfc9;
+ *(uint32_t*)0x2000019c = 0;
+ *(uint32_t*)0x200001a0 = 0;
+ *(uint8_t*)0x200001a4 = 0;
+ *(uint8_t*)0x200001a5 = 0;
+ *(uint16_t*)0x200001a6 = htobe16(0);
+ *(uint32_t*)0x200001a8 = 0x14;
+ *(uint16_t*)0x200001ac = 0x11;
+ *(uint16_t*)0x200001ae = 1;
+ *(uint32_t*)0x200001b0 = 0;
+ *(uint32_t*)0x200001b4 = 0;
+ *(uint8_t*)0x200001b8 = 0;
+ *(uint8_t*)0x200001b9 = 0;
+ *(uint16_t*)0x200001ba = htobe16(0xa);
+ *(uint64_t*)0x20000c08 = 0x3c;
+ *(uint64_t*)0x20000c58 = 1;
+ *(uint64_t*)0x20000c60 = 0;
+ *(uint64_t*)0x20000c68 = 0;
+ *(uint32_t*)0x20000c70 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000c40ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5d79326609112f7037a8f97b02d1ccccc1da943e.c b/syzkaller-repros/linux/5d79326609112f7037a8f97b02d1ccccc1da943e.c
new file mode 100644
index 0000000..e59000d
--- /dev/null
+++ b/syzkaller-repros/linux/5d79326609112f7037a8f97b02d1ccccc1da943e.c
@@ -0,0 +1,34 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+const int kInitNetNsFd = 239;
+
+static long syz_init_net_socket(volatile long domain, volatile long type,
+ volatile long proto)
+{
+ return syscall(__NR_socket, domain, type, proto);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_init_net_socket(0x1f, 5, 2);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000180 = 0;
+ syscall(__NR_getsockopt, r[0], 0x112ul, 0xeul, 0ul, 0x20000180ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5e57e5f0dc65684681141a35c4f202efe41b2578.c b/syzkaller-repros/linux/5e57e5f0dc65684681141a35c4f202efe41b2578.c
new file mode 100644
index 0000000..8bfdd98
--- /dev/null
+++ b/syzkaller-repros/linux/5e57e5f0dc65684681141a35c4f202efe41b2578.c
@@ -0,0 +1,577 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0x20;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0x40;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint32_t*)0x200000b8 = 0;
+ *(uint32_t*)0x200000bc = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000040ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_ioctl, r[1], 0x4b61ul, 0x20000080ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5ed56f4caf5b58ccf3c013d5798b2fb61b40eba8.c b/syzkaller-repros/linux/5ed56f4caf5b58ccf3c013d5798b2fb61b40eba8.c
new file mode 100644
index 0000000..19ce5ed
--- /dev/null
+++ b/syzkaller-repros/linux/5ed56f4caf5b58ccf3c013d5798b2fb61b40eba8.c
@@ -0,0 +1,1107 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 9; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0x0};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_perf_event_open, 0ul, 0, -1ul, -1, 0ul);
+ break;
+ case 1:
+ syscall(__NR_setsockopt, -1, 0x29ul, 0x3bul, 0ul, 0ul);
+ break;
+ case 2:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 3:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 4:
+ res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 5:
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint64_t*)0x200001d0 = 0x20000180;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint64_t*)0x20000188 = 0;
+ *(uint64_t*)0x200001d8 = 1;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001f0 = 0;
+ syscall(__NR_sendmsg, r[2], 0x200001c0ul, 0ul);
+ break;
+ case 6:
+ *(uint32_t*)0x20000200 = 0x14;
+ res = syscall(__NR_getsockname, r[2], 0x20000100ul, 0x20000200ul);
+ if (res != -1)
+ r[3] = *(uint32_t*)0x20000104;
+ break;
+ case 7:
+ syscall(__NR_sendmsg, r[1], 0ul, 0ul);
+ break;
+ case 8:
+ *(uint64_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000088 = 0x325;
+ *(uint64_t*)0x20000090 = 0x20000040;
+ *(uint64_t*)0x20000040 = 0x200000c0;
+ *(uint32_t*)0x200000c0 = 0x28;
+ *(uint16_t*)0x200000c4 = 0x10;
+ *(uint16_t*)0x200000c6 = 0x825;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint8_t*)0x200000d0 = 0;
+ *(uint8_t*)0x200000d1 = 0;
+ *(uint16_t*)0x200000d2 = 0;
+ *(uint32_t*)0x200000d4 = r[3];
+ *(uint32_t*)0x200000d8 = 3;
+ *(uint32_t*)0x200000dc = 0;
+ *(uint16_t*)0x200000e0 = 8;
+ *(uint16_t*)0x200000e2 = 0xa;
+ *(uint8_t*)0x200000e4 = 0x14;
+ *(uint64_t*)0x20000048 = 0x28;
+ *(uint64_t*)0x20000098 = 1;
+ *(uint64_t*)0x200000a0 = 0;
+ *(uint64_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ inject_fault(35);
+ syscall(__NR_sendmsg, r[0], 0x20000080ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/5fe2408910fc851794ba02c468fabe70c56ea3b6.c b/syzkaller-repros/linux/5fe2408910fc851794ba02c468fabe70c56ea3b6.c
new file mode 100644
index 0000000..8339c75
--- /dev/null
+++ b/syzkaller-repros/linux/5fe2408910fc851794ba02c468fabe70c56ea3b6.c
@@ -0,0 +1,425 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x200004c0, "/dev/tty1#\000", 11);
+ res = syz_open_dev(0x200004c0, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x5608ul, 0);
+ memcpy((void*)0x20000100, "/dev/tty1#\000", 11);
+ syz_open_dev(0x20000100, 4, 0x127200);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/60c210359008690dc9061473b0307f2ec1e55f71.c b/syzkaller-repros/linux/60c210359008690dc9061473b0307f2ec1e55f71.c
new file mode 100644
index 0000000..d79f293
--- /dev/null
+++ b/syzkaller-repros/linux/60c210359008690dc9061473b0307f2ec1e55f71.c
@@ -0,0 +1,326 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0x20000000;
+ *(uint64_t*)0x20000000 = 0;
+ *(uint64_t*)0x20000008 = 0xfffffffffffffe97;
+ *(uint64_t*)0x20000198 = 1;
+ *(uint64_t*)0x200001a0 = 0;
+ *(uint64_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001b0 = 0;
+ syscall(__NR_sendmsg, -1, 0x20000180ul, 0ul);
+ *(uint64_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint64_t*)0x20000050 = 0x20000000;
+ *(uint64_t*)0x20000000 = 0x20000300;
+ memcpy((void*)0x20000300,
+ "\x34\x01\x00\x00\x10\x00\x05\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00",
+ 20);
+ *(uint32_t*)0x20000314 = 0;
+ memcpy(
+ (void*)0x20000318,
+ "\x00\x00\x00\x00\x04\x00\x00\x00\x08\x01\x12\x00\x0c\x00\x01\x00\x6d\x61"
+ "\x63\x76\x6c\x61\x6e\x00\xf8\x00\x0f\x00\x4c\x00\x05\x17\x0a\x00\x04\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\xeb\xff\xd1\x1b\xf5\x46\x6b\xca"
+ "\x00\x00\x0a\x00\x04\x00\xea\x9c\x2f\x85\x34\x0b\x00\x00\x0a\x00\x04\x00"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\x00\x00\x0a\x00\x04\x00\x00\xaa\xaa\xaa\xaa\xbb"
+ "\x20\x00\x0a\x00\x04\x00\xaa\xaa\xaa\xaa\xaa\xbb\x00\x00\x0a\x00\x04\x00"
+ "\xaa\xaa\xaa\xaa\xaa\xbb\x00\x00\x08\x00\x01\x00\x10\x00\x00\x00\x0a\x00"
+ "\x04\x00\xaa\xaa\xaa\xaa\xaa\xaa\x00\x00\x0a\x00\x04\x00\xaa\xaa\xaa\xaa"
+ "\xaa\x23\x00\x00\x08\x00\x03\x00\x03\x00\x00\x00\x09\xbc\x03\x00\x02\x00"
+ "\x00\x00\x64\x00\x05\x00\x0a\x19\x04\x00\x01\x80\xc2\x00\x00\x03\x00\x00"
+ "\x0a\x00\x04\x00\xff\xff\xff\xff\xff\xff\x00\x00\x0a\x00\x04\x00\xaa\xaa"
+ "\xaa\xaa\xaa\x24\x00\x00\x0a\x00\x04\x00\xff\xff\xff\xff\xff\xff\x00\x00"
+ "\x0a\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\xfd\x03\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x0a\x00\x04\x00\x01\x80\xc2\x00\x00\x02\x00\x00"
+ "\x0a\x00\x04\x00\x10\xc7\x84\x01\x15\x64\x00\x00\x08\x00\x03\x00\x00\x00"
+ "\x00\x02\x0a\x00\x05\x00\x04\x00\x00\x00\x00\x00\x00\x00\x8c\xeb\xcf\xed"
+ "\xe9\x0c\x55\xc3\x1a\xd1\x37\x11\x35\x54\x10\x3d\xd0\xe6\xe3\xae\xf5\xc1"
+ "\xef\x84\xf2\x7b\x53\x5b\x60\x13\x1f\x59\x1d\xd4\x46\x44\x68\x82\x2f\xfb"
+ "\x39\x9f\x5b\x35\x99\x2f\xce\x4b\xa7\x5b\x5d\x45\x49\xfe\x21\x2c\xcb\xfb"
+ "\x1f\xe6\x47\x94\xc2\x2c\x97\x60\x1e\xdd\x8c\x5b\xe3\xac\x4e\x10\xd4\x00"
+ "\x01\xb5\x8b\x22\x2c\x3b\x29\xb3\x8e\x82\xc9\x76\xfb\x92\xf6\x93\x4b\xa6"
+ "\x2d\xe4\xab\x26\x6b\xe7\xa8\xaa\xcd\x9f\xe1\xcb\x8a\x55\xe4\x64\x50\x05"
+ "\xd1\x6a\x4e\xab\x6c\xf5\x78\xca\x88\x79\xb7\x1c\xca\xc6\x76\x6e\x4b\x4e"
+ "\x0d\x58\xdd\x22\xa4\x9d\x94\x92\xda\xf9\x3e\xab\x65\x86\xdd\xed\x12\xb1"
+ "\x88\xd3\x1f\x89\xc1\x50\x54\xf7\xc5\x32\xe2\x0f\x90\x41\x2d\x1d\x94\x46"
+ "\xa5\x93\xef\xb1\x2e\x65\xae\x2b\x01\xf9\xa7\x42\x99\xc3\x1e\x0f\xb5\x99"
+ "\x33\x00\x00\x00\x00\xf6\x60\x3b\x38\x9e\x34\xf1\x93\xcc\x94\xf6\x15\x27"
+ "\x41\x8a\x02\xa8\x99\x35\xff\x0d\xec\x3a\xd4\x8e\x26\x28\xd0\xd2\x7c\xa3"
+ "\x2c\x71\x9c\xb9\xc6\xb9\x31\x77\x24\x6e\x46\xe9\x4a\x0d\x4e\x23\x0e\x3d"
+ "\xe6\x15\x03\x56\x6e\xb2\xfe\xb8\xad\xd3\xcf\x3b\xce\x0e\xd5\x85\x3a\x8b"
+ "\x21\xe8\x54\x1b\x04\x6d\x5e\xca\xeb\xf4\x83\x2f\x0b\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 567);
+ *(uint64_t*)0x20000008 = 0x134;
+ *(uint64_t*)0x20000058 = 1;
+ *(uint64_t*)0x20000060 = 0;
+ *(uint64_t*)0x20000068 = 0;
+ *(uint32_t*)0x20000070 = 0;
+ syscall(__NR_sendmsg, -1, 0x20000040ul, 0x10ul);
+ res = syscall(__NR_socket, 0x10ul, 0x80002ul, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000140 = 0x68000000;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0x20000100;
+ *(uint64_t*)0x20000158 = 0;
+ *(uint64_t*)0x20000160 = 0x20000100;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmmsg, r[0], 0x20000140ul, 0x492492492492805ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6117de858dc67fea5b42b327761d2fb973c32fcc.c b/syzkaller-repros/linux/6117de858dc67fea5b42b327761d2fb973c32fcc.c
new file mode 100644
index 0000000..729c064
--- /dev/null
+++ b/syzkaller-repros/linux/6117de858dc67fea5b42b327761d2fb973c32fcc.c
@@ -0,0 +1,433 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000180, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000180ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ inject_fault(15);
+ syscall(__NR_ioctl, r[0], 0x4611ul, 0x400ffeul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/64652ef82318ae833b252bb22dc16e13f344d6d5.c b/syzkaller-repros/linux/64652ef82318ae833b252bb22dc16e13f344d6d5.c
new file mode 100644
index 0000000..c976600
--- /dev/null
+++ b/syzkaller-repros/linux/64652ef82318ae833b252bb22dc16e13f344d6d5.c
@@ -0,0 +1,511 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+void execute_one(void)
+{
+ *(uint8_t*)0x20000c80 = 0x12;
+ *(uint8_t*)0x20000c81 = 1;
+ *(uint16_t*)0x20000c82 = 0;
+ *(uint8_t*)0x20000c84 = 0x69;
+ *(uint8_t*)0x20000c85 = 0x48;
+ *(uint8_t*)0x20000c86 = 0xdb;
+ *(uint8_t*)0x20000c87 = 8;
+ *(uint16_t*)0x20000c88 = 0x2040;
+ *(uint16_t*)0x20000c8a = 0xd300;
+ *(uint16_t*)0x20000c8c = 0xbd5a;
+ *(uint8_t*)0x20000c8e = 0;
+ *(uint8_t*)0x20000c8f = 0;
+ *(uint8_t*)0x20000c90 = 0;
+ *(uint8_t*)0x20000c91 = 1;
+ *(uint8_t*)0x20000c92 = 9;
+ *(uint8_t*)0x20000c93 = 2;
+ *(uint16_t*)0x20000c94 = 0x10e;
+ *(uint8_t*)0x20000c96 = 1;
+ *(uint8_t*)0x20000c97 = 0;
+ *(uint8_t*)0x20000c98 = 0;
+ *(uint8_t*)0x20000c99 = 0;
+ *(uint8_t*)0x20000c9a = 0;
+ *(uint8_t*)0x20000c9b = 9;
+ *(uint8_t*)0x20000c9c = 4;
+ *(uint8_t*)0x20000c9d = 0xa1;
+ *(uint8_t*)0x20000c9e = 0;
+ *(uint8_t*)0x20000c9f = 4;
+ *(uint8_t*)0x20000ca0 = 0x9f;
+ *(uint8_t*)0x20000ca1 = 0xf7;
+ *(uint8_t*)0x20000ca2 = 0xd6;
+ *(uint8_t*)0x20000ca3 = 0;
+ *(uint8_t*)0x20000ca4 = 7;
+ *(uint8_t*)0x20000ca5 = 5;
+ *(uint8_t*)0x20000ca6 = 5;
+ *(uint8_t*)0x20000ca7 = 0x10;
+ *(uint16_t*)0x20000ca8 = 6;
+ *(uint8_t*)0x20000caa = 8;
+ *(uint8_t*)0x20000cab = 4;
+ *(uint8_t*)0x20000cac = 1;
+ *(uint8_t*)0x20000cad = 2;
+ *(uint8_t*)0x20000cae = 0;
+ *(uint8_t*)0x20000caf = 7;
+ *(uint8_t*)0x20000cb0 = 5;
+ *(uint8_t*)0x20000cb1 = 1;
+ *(uint8_t*)0x20000cb2 = 0x10;
+ *(uint16_t*)0x20000cb3 = 6;
+ *(uint8_t*)0x20000cb5 = 3;
+ *(uint8_t*)0x20000cb6 = 8;
+ *(uint8_t*)0x20000cb7 = 9;
+ *(uint8_t*)0x20000cb8 = 7;
+ *(uint8_t*)0x20000cb9 = 5;
+ *(uint8_t*)0x20000cba = 0x3f;
+ *(uint8_t*)0x20000cbb = 0x10;
+ *(uint16_t*)0x20000cbc = 5;
+ *(uint8_t*)0x20000cbe = 4;
+ *(uint8_t*)0x20000cbf = 9;
+ *(uint8_t*)0x20000cc0 = 0xf9;
+ *(uint8_t*)0x20000cc1 = 2;
+ *(uint8_t*)0x20000cc2 = 4;
+ *(uint8_t*)0x20000cc3 = 2;
+ *(uint8_t*)0x20000cc4 = 0xa;
+ *(uint8_t*)0x20000cc5 = 7;
+ *(uint8_t*)0x20000cc6 = 5;
+ *(uint8_t*)0x20000cc7 = 2;
+ *(uint8_t*)0x20000cc8 = 0x10;
+ *(uint16_t*)0x20000cc9 = 0;
+ *(uint8_t*)0x20000ccb = 3;
+ *(uint8_t*)0x20000ccc = 4;
+ *(uint8_t*)0x20000ccd = 8;
+ *(uint8_t*)0x20000cce = 2;
+ *(uint8_t*)0x20000ccf = 0xf;
+ *(uint8_t*)0x20000cd0 = 0xd0;
+ *(uint8_t*)0x20000cd1 = 0x23;
+ memcpy(
+ (void*)0x20000cd2,
+ "\x20\x32\xc7\x8e\x97\x7d\x8e\xc6\xce\x91\xf4\x35\xce\x8b\xb4\x90\xd6\x75"
+ "\x57\x54\x24\x21\xdd\xeb\xcf\x03\x2f\x44\x52\xdb\xb0\xfb\x0c\x86\x92\x5e"
+ "\x36\x75\x31\x8e\x6b\x98\x65\x08\x34\x6a\x8c\x3c\x46\x5f\x02\xfa\x28\x64"
+ "\x93\x44\xe9\xf1\x79\xf6\x4a\x4d\x01\xc4\x17\x0a\xd7\xcf\x49\xe7\x02\xce"
+ "\x0a\x9a\xa8\xe8\x47\xca\xc1\xcf\xeb\x3a\x52\x83\x06\x96\x82\x0f\x1c\x83"
+ "\x23\x53\xf0\x97\x2d\x03\xc7\x78\xc3\xcb\x63\xdc\xfe\xa9\xad\x9d\x17\x8d"
+ "\xfe\x86\xf5\xbf\xc5\x29\xd7\x94\x76\x5f\xd4\x69\x43\x37\x1c\x0b\xfa\x86"
+ "\x04\x52\xc4\xee\x91\x86\xed\x30\x38\x36\x52\x59\x6c\x7d\x84\xf6\x96\x05"
+ "\xde\xfc\x0e\x19\x68\x4c\xa8\xf5\x19\xcc\x08\x66\xb8\xd7\x93\x2a\x8e\xd2"
+ "\x4a\xe9\x62\xfd\x93\xe0\x2f\xf6\x9e\x71\x15\x74\x71\x78\x63\x1f\x64\x33"
+ "\xb1\x04\xef\xf7\x29\xf3\x38\xf1\xf2\x1d\xa1\x7c\xb0\x24\xa9\x5e\x18\x7e"
+ "\x5e\x84\x33\xcb\x68\xe7\x41\x31",
+ 206);
+ syz_usb_connect(2, 0x120, 0x20000c80, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/64c6ad900871a32499005fa874244be1847e3b2c.c b/syzkaller-repros/linux/64c6ad900871a32499005fa874244be1847e3b2c.c
new file mode 100644
index 0000000..ff8255e
--- /dev/null
+++ b/syzkaller-repros/linux/64c6ad900871a32499005fa874244be1847e3b2c.c
@@ -0,0 +1,405 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x200000c0, "/dev/ptmx\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200000c0ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0xf;
+ syscall(__NR_ioctl, r[0], 0x5423ul, 0x20000040ul);
+ syscall(__NR_ioctl, r[0], 0x400455c8ul, 9ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6592b2397fe3d588ba3d54d3cc48a769a300c2a1.c b/syzkaller-repros/linux/6592b2397fe3d588ba3d54d3cc48a769a300c2a1.c
new file mode 100644
index 0000000..a2eecbc
--- /dev/null
+++ b/syzkaller-repros/linux/6592b2397fe3d588ba3d54d3cc48a769a300c2a1.c
@@ -0,0 +1,118 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ long res = 0;
+ memcpy((void*)0x20000000, "/dev/video#", 12);
+ res = syz_open_dev(0x20000000, 0xe15, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000100 = 5;
+ *(uint32_t*)0x20000104 = 2;
+ *(uint32_t*)0x20000108 = 1;
+ *(uint32_t*)0x2000010c = 0;
+ *(uint32_t*)0x20000110 = 0;
+ syscall(__NR_ioctl, r[0], 0xc0145608, 0x20000100);
+ *(uint32_t*)0x20000140 = 0x5f56e7c2;
+ *(uint32_t*)0x20000144 = 0xffff;
+ *(uint32_t*)0x20000148 = 2;
+ *(uint32_t*)0x20000150 = 2;
+ *(uint16_t*)0x20000158 = 4;
+ *(uint16_t*)0x2000015a = 0xfff;
+ *(uint16_t*)0x2000015c = 0x400;
+ *(uint16_t*)0x2000015e = 0x81;
+ *(uint16_t*)0x20000160 = 5;
+ *(uint16_t*)0x20000162 = 5;
+ *(uint16_t*)0x20000164 = 0;
+ *(uint16_t*)0x20000166 = 5;
+ *(uint16_t*)0x20000168 = 0xfff8;
+ *(uint16_t*)0x2000016a = 7;
+ *(uint16_t*)0x2000016c = 0x40;
+ *(uint16_t*)0x2000016e = 0x1f;
+ *(uint16_t*)0x20000170 = 8;
+ *(uint16_t*)0x20000172 = 1;
+ *(uint16_t*)0x20000174 = 0xead8;
+ *(uint16_t*)0x20000176 = 6;
+ *(uint16_t*)0x20000178 = 9;
+ *(uint16_t*)0x2000017a = 3;
+ *(uint16_t*)0x2000017c = 0x7b;
+ *(uint16_t*)0x2000017e = 5;
+ *(uint16_t*)0x20000180 = 7;
+ *(uint16_t*)0x20000182 = 0x645;
+ *(uint16_t*)0x20000184 = 0x409;
+ *(uint16_t*)0x20000186 = 3;
+ *(uint16_t*)0x20000188 = 0x100;
+ *(uint16_t*)0x2000018a = -1;
+ *(uint16_t*)0x2000018c = 0xfff;
+ *(uint16_t*)0x2000018e = 9;
+ *(uint16_t*)0x20000190 = 0;
+ *(uint16_t*)0x20000192 = 0x97fc;
+ *(uint16_t*)0x20000194 = 0x7ff;
+ *(uint16_t*)0x20000196 = 5;
+ *(uint16_t*)0x20000198 = 5;
+ *(uint16_t*)0x2000019a = 6;
+ *(uint16_t*)0x2000019c = 0x100;
+ *(uint16_t*)0x2000019e = 0xf413;
+ *(uint16_t*)0x200001a0 = 3;
+ *(uint16_t*)0x200001a2 = 0x1aef;
+ *(uint16_t*)0x200001a4 = -1;
+ *(uint16_t*)0x200001a6 = 8;
+ *(uint16_t*)0x200001a8 = 0x80;
+ *(uint16_t*)0x200001aa = 1;
+ *(uint16_t*)0x200001ac = 7;
+ *(uint16_t*)0x200001ae = 0xf870;
+ *(uint16_t*)0x200001b0 = 7;
+ *(uint16_t*)0x200001b2 = 4;
+ *(uint16_t*)0x200001b4 = 1;
+ *(uint16_t*)0x200001b6 = 6;
+ *(uint16_t*)0x200001b8 = 0xd4a;
+ *(uint32_t*)0x200001bc = 0x34;
+ *(uint32_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c4 = 0;
+ *(uint32_t*)0x20000220 = 0;
+ *(uint32_t*)0x20000224 = 0;
+ *(uint32_t*)0x20000228 = 0;
+ *(uint32_t*)0x2000022c = 0;
+ *(uint32_t*)0x20000230 = 0;
+ *(uint32_t*)0x20000234 = 0;
+ *(uint32_t*)0x20000238 = 0;
+ *(uint32_t*)0x2000023c = 0;
+ syscall(__NR_ioctl, r[0], 0xc100565c, 0x20000140);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6665a2e0c54f2675589258ad04ffa1e5fc76f071.c b/syzkaller-repros/linux/6665a2e0c54f2675589258ad04ffa1e5fc76f071.c
new file mode 100644
index 0000000..ff28aa3
--- /dev/null
+++ b/syzkaller-repros/linux/6665a2e0c54f2675589258ad04ffa1e5fc76f071.c
@@ -0,0 +1,413 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/loop.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+struct fs_image_segment {
+ void* data;
+ uintptr_t size;
+ uintptr_t offset;
+};
+
+#define IMAGE_MAX_SEGMENTS 4096
+#define IMAGE_MAX_SIZE (129 << 20)
+
+#define sys_memfd_create 319
+
+static unsigned long fs_image_segment_check(unsigned long size,
+ unsigned long nsegs, long segments)
+{
+ unsigned long i;
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ if (nsegs > IMAGE_MAX_SEGMENTS)
+ nsegs = IMAGE_MAX_SEGMENTS;
+ for (i = 0; i < nsegs; i++) {
+ if (segs[i].size > IMAGE_MAX_SIZE)
+ segs[i].size = IMAGE_MAX_SIZE;
+ segs[i].offset %= IMAGE_MAX_SIZE;
+ if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
+ segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
+ if (size < segs[i].offset + segs[i].offset)
+ size = segs[i].offset + segs[i].offset;
+ }
+ if (size > IMAGE_MAX_SIZE)
+ size = IMAGE_MAX_SIZE;
+ return size;
+}
+
+static long syz_read_part_table(volatile unsigned long size,
+ volatile unsigned long nsegs,
+ volatile long segments)
+{
+ char loopname[64], linkname[64];
+ int loopfd, err = 0, res = -1;
+ unsigned long i, j;
+ NONFAILING(size = fs_image_segment_check(size, nsegs, segments));
+ int memfd = syscall(sys_memfd_create, "syz_read_part_table", 0);
+ if (memfd == -1) {
+ err = errno;
+ goto error;
+ }
+ if (ftruncate(memfd, size)) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ for (i = 0; i < nsegs; i++) {
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ int res1 = 0;
+ NONFAILING(res1 =
+ pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset));
+ if (res1 < 0) {
+ }
+ }
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
+ loopfd = open(loopname, O_RDWR);
+ if (loopfd == -1) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ if (errno != EBUSY) {
+ err = errno;
+ goto error_close_loop;
+ }
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ usleep(1000);
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ err = errno;
+ goto error_close_loop;
+ }
+ }
+ struct loop_info64 info;
+ if (ioctl(loopfd, LOOP_GET_STATUS64, &info)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ info.lo_flags |= LO_FLAGS_PARTSCAN;
+ if (ioctl(loopfd, LOOP_SET_STATUS64, &info)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ res = 0;
+ for (i = 1, j = 0; i < 8; i++) {
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llup%d", procid, (int)i);
+ struct stat statbuf;
+ if (stat(loopname, &statbuf) == 0) {
+ snprintf(linkname, sizeof(linkname), "./file%d", (int)j++);
+ if (symlink(loopname, linkname)) {
+ }
+ }
+ }
+error_clear_loop:
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+error_close_loop:
+ close(loopfd);
+error_close_memfd:
+ close(memfd);
+error:
+ errno = err;
+ return res;
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 3; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ NONFAILING(memcpy((void*)0x20000040, "/dev/null\000", 10));
+ res =
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0x100ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ NONFAILING(*(uint32_t*)0x200004c0 = 2);
+ NONFAILING(*(uint32_t*)0x200004c4 = 0);
+ NONFAILING(*(uint32_t*)0x200004c8 = 0x1c);
+ NONFAILING(*(uint32_t*)0x200004cc = 0x15);
+ NONFAILING(*(uint32_t*)0x200004d0 = 0x143);
+ NONFAILING(*(uint64_t*)0x200004d8 = 0x200000c0);
+ NONFAILING(memcpy(
+ (void*)0x200000c0,
+ "\x8b\x8e\x8e\xcd\x7b\xd8\x86\x73\x3a\x51\xd4\x51\x64\xcb\xcb\x52\x4c"
+ "\x91\x77\x54\x91\xb2\xff\x4a\x50\x6b\x65\x06\x73\xd3\x2f\xf0\xbf\x1a"
+ "\x36\x81\x42\x47\x59\x0a\x1f\xe5\x0c\xa1\xbd\x9e\xf8\x72\x5d\xf1\x5d"
+ "\x2f\x9b\x47\x20\x14\x86\x41\xcb\xc0\xdb\x92\x29\xd8\x67\xb8\xa4\xa1"
+ "\x28\x2f\xa2\x7f\x69\x13\x98\x12\xf2\x4e\x08\x63\x7b\x6a\x32\x4f\x03"
+ "\x5b\x15\xde\x8f\x4a\x6a\x78\xe2\x9e\x3d\x6c\x5e\xac\x55\x1c\x0b\xb3"
+ "\xc8\x4a\x6c\x63\xd0\xb7\xf7\x1d\xcf\x07\xa7\x1b\x8c\xdb\x25\x15\x14"
+ "\x14\x0e\xb8\x56\x6c\x87\x5c\xf9\xf8\xd1\x4a\x4b\xdb\xf2\xb0\xd7\x22"
+ "\xd3\x97\x4c\x46\xd1\x63\x28\xb6\xbd\xf8\xeb\x7a\x0a\x86\x4a\xb8\x68"
+ "\xfb\x88\xbe\x41\x99\xc2\x80\xe4\x1d\xef\x97\xfb\x2c\x21\x7e\x15\x06"
+ "\x3a\x20\x94\xb4\x9a\x54\xee\x32\xdb\x46\x46\xc5\xdb\x4b\x2a\xdf\x56"
+ "\x15\x9c\x6c\x39\xbb\xba\x4a\x42\x34\x08\x01\x67\xea\x6c\x8d\x7f\x07"
+ "\x09\x49\xe5\x1e\xa3\x4b\xba\x37\xcd\xaf\x44\x5a\xd1\xaa\x6a\x2f\xc7"
+ "\x99\x2f\x36\x32\x35\x44\xe9\x75\x1f\x25\x5b\x1d\x7e\x8e\xd5\x15\xbc"
+ "\x8d\x0a\x10\x16\x77\xa9\x96\xf3\x4a\xc8\xd7\xfd\xf8\xd2\x75\x7c\x84"
+ "\x11\xca\x3d\x50\x9d\x48\xe9\xcb\x75\x28\x9f\xad\xdf\xc6\xcd\x60\x57"
+ "\xab\xeb\x96\xae\xb1\x0d\x29\xd8\xce\x4d\x4c\xd2\x6d\xda\xb7\xf2\xa2"
+ "\x85\x69\x65\xc0\xf1\x34\x20\x75\x8c\xcd\xce\xc9\xe5\x61\x68\xf6\x4e"
+ "\x3b\x8d\x8e\xc7\x32\xdf\x3b\x70\x7c\x7b\xe0\x68\xaa\xc2\xcc\xa9\x72"
+ "\x9e\x53\x88\xb8\x63\x9d\xac\x8d\xae\x87\x4a\xda\x70\x52\xf5\x34\xd1"
+ "\xde\x34\x70\x6b\xa8\x64\x85\xfa\x49\x2b\xfa\xd5\x3a\x91\x64\x24\x6d"
+ "\xe8\x54\xe8\x26\xb1\xf0\x5f\x8e\x9c\xb9\xb6\x71\x42\xf7\x18\x39\x58"
+ "\x94\x7d\x17\x3f\x74\x9c\x95\x2f\x1d\xa4\xfc\x9b\x54\x8b\x8e\x7c\x85"
+ "\xf1\x7d\x27\x96\x4b\xcc\xcf\xf4\xac\x6c\x0e\x92\x67\x2d\x59\x55\x84"
+ "\x52\x62\xa9\xb9\xa1\x56\xc4\x2f\x10\xf0\x0a\xc9\x00\x34\xd6\x97\xa3"
+ "\x19\x7f\x60\xc8\xff\x00\xc9\xae\xc2\x0d\x29\x8d\xb4\x44\xa5\x58\x56"
+ "\x45\x52\x0b\x63\x6c\xf0\xc6\x05\x15\xd8\xde\x1b\xde\xf5\x32\xe3\xfc"
+ "\xfe\x2e\xbd\xfc\x30\xf2\x82\x7d\x58\x2a\x4a\xf0\xc2\xa5\x0f\xc7\x3b"
+ "\x6c\x45\x6e\x74\x09\xfa\x15\x0e\xaa\x60\x4f\x1d\xc5\x5d\x90\x76\x2b"
+ "\x42\x71\xdb\x6d\xb9\x7d\x8f\x97\x23\xd3\xc5\x72\x73\x2d\x96\x66\x32"
+ "\xf9\x2d\x74\x7a\x85\xd0\x20\x12\x9c\x9b\xe0\x32\xbc\x2c\x9a\xd0\x79"
+ "\x89\x59\x04\xbe\x09\x00\xa6\x0f\x1d\x48\x22\x78\xac\x53\xd5\xf3\xcc"
+ "\xde\x0a\xfd\x88\xe4\xc2\x45\x1f\x31\x02\xac\x61\x0b\x80\xf4\x4d\xa1"
+ "\x97\x33\x5d\x14\x9b\x08\xb1\xcc\x74\x81\xe4\x63\x91\xe8\x42\x5e\x9d"
+ "\x74\x68\x15\xb4\x24\xda\x50\xf0\xaf\xe5\x25\xdb\x11\xe1\x85\xd5\x3e"
+ "\xab\xa5\x6b\xf5\xc9\xa8\x26\x50\x95\xa9\x3d\x20\x65\xfe\xe0\xc3\xb0"
+ "\xa9\x65\xa8\xaa\xbd\x7c\xb5\xe9\xc6\x14\x7e\x46\x67\xb2\xe6\xf6\xd7"
+ "\x6c\x33\xa4\x53\x8c\xb7\x63\x33\xbd\x8d\x78\xd1\xa7\xc3\x39\x60\x92"
+ "\x62\xb4\x62\x23\xe1\x31\x3a\x8e\xa1\x7a\x96\x5a\xcb\xef\xd3\xaf\x90"
+ "\x0c\x32\x49\xe7\x72\xdd\xf5\xa8\x5b\x65\x11\xaf\xba\x96\xcf\xd9\xbe"
+ "\x98\xea\x75\x9b\x08\xaa\xb9\x40\x99\x43\x40\x0d\x24\x15\x13\x65\xe2"
+ "\x0d\x92\x62\xff\x05\x6c\x5e\x76\x04\xde\x18\xdd\x56\xfe\xb1\x09\x28"
+ "\x0d\x3d\x70\xda\x6b\x14\x0b\x53\xe0\x3a\xee\xf3\x30\xed\xae\x88\x4f"
+ "\x84\x5a\x27\xb6\xce\x7a\x3e\x5d\x6f\x08\x02\x6c\xc3\x59\xf2\x55\x98"
+ "\x9e\x94\xfc\x2b\x6d\xf4\x75\x1f\x94\xf5\x18\xb8\x19\x4d\x1c\xd2\x0f"
+ "\xee\xc2\x55\xf8\x5d\x51\x79\xbb\xb9\xa1\xe9\xcc\xac\x93\xc1\x4a\x00"
+ "\x86\xe8\x60\x50\xc0\xcc\x96\xfc\x5d\xc6\x7b\x36\x47\x59\x99\xd3\x8b"
+ "\x34\xd3\x9c\x39\xc6\x0b\x67\x91\x7b\xab\xc8\x29\x82\xf5\x39\xf3\x97"
+ "\x18\x99\x41\xca\x38\x28\x1d\x17\xc9\x9c\x32\x73\xfb\x3b\xb7\x27\x82"
+ "\xe5\x81\xa8\x7c\x39\xf6\x26\x30\x5a\x49\x96\xa0\xf1\x9b\xf8\x59\xd5"
+ "\x46\x0b\x5b\x60\x7d\xfc\xd7\x48\xc3\x24\x61\xa9\xec\xdc\x1f\xd5\x73"
+ "\x86\x94\x71\xe1\x1e\x68\x55\x05\x16\x62\x0a\x94\xcb\x51\x95\x8e\x75"
+ "\xbd\xd3\x3e\x76\xf8\x0a\x4f\x23\xc4\x7d\x07\x21\xcc\xd1\x17\xa6\xe7"
+ "\x0b\x8d\xa8\x30\x20\x5b\x80\x48\x94\x26\x83\xc7\x0c\x35\x51\x00\x92"
+ "\x72\x9e\x25\xdf\x9e\xc1\x99\xe5\x50\x6e\x24\x08\xf8\x1e\x77\x8b\x12"
+ "\x2e\xb8\xc0\xf7\x6f\xbd\xb7\x65\xfa\x51\x9a\xe2\x8e\xef\x06\x3b\x81"
+ "\x22\x1d\xe4\xbe\xc7\x02\x80\xf4\xd1\xfe\x67\xad\xf6\x78\xfe\x39\x16"
+ "\xd2\x6d\x21\xff\xb8\xbc\xdd\xa0\x6d\x1d\x17\x70\x71\xd3\x15\xf0\x7d"
+ "\xc5\xa2\x6d\x8d\x7f\x68\xaf\x60\xdf\x6f\xb6\x74\xe5\xae\x14\x45\xd4"
+ "\x1c\x53\x4e\xd4\x23\xdc\x0c\xa5\x8b\xc9\x5d\x87\xbe\x25\x03\xac\xf7"
+ "\xef\x62\xc4\x0c",
+ 1024));
+ syscall(__NR_ioctl, r[0], 0x4b72ul, 0x200004c0ul);
+ break;
+ case 2:
+ NONFAILING(*(uint64_t*)0x20000080 = 0x20000000);
+ NONFAILING(memcpy(
+ (void*)0x20000000,
+ "\x02\x01\xa5\xff\xff\xff\x01\x00\x00\x00\xff\x07\x00\x00\x00\xff\xff"
+ "\xff\xfd\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\xff\xff\xff"
+ "\x85\x00\x00\x00\x00\x00\x00\x00\x88\x77\x00\x72\x00\x30\xb5\x82\x92"
+ "\x37\xc3\x00\x00\x00\x00\x00\x00\x80\x00\x00\x55\xaa",
+ 64));
+ NONFAILING(*(uint64_t*)0x20000088 = 0x40);
+ NONFAILING(*(uint64_t*)0x20000090 = 0x1c0);
+ syz_read_part_table(0, 0x1bf, 0x20000080);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/666cf8be893ec25bbf0e3ed7596dc30e1f3518ba.c b/syzkaller-repros/linux/666cf8be893ec25bbf0e3ed7596dc30e1f3518ba.c
new file mode 100644
index 0000000..95b4977
--- /dev/null
+++ b/syzkaller-repros/linux/666cf8be893ec25bbf0e3ed7596dc30e1f3518ba.c
@@ -0,0 +1,616 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10, 3, 0);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_getsockopt, r[0], 1, 0x11, 0, 0);
+ NONFAILING(memcpy((void*)0x20000200, "./file1\000", 8));
+ syscall(__NR_mkdir, 0x20000200, 0);
+ NONFAILING(memcpy((void*)0x200000c0, "./file0\000", 8));
+ syscall(__NR_mkdir, 0x200000c0, 0);
+ NONFAILING(memcpy((void*)0x20000300, "./file0\000", 8));
+ NONFAILING(memcpy((void*)0x20000100, "overlay\000", 8));
+ NONFAILING(memcpy((void*)0x200002c0,
+ "upperdir=./file0,lowerdir=.:file0,workdir=./file1", 49));
+ syscall(__NR_mount, 0x400000, 0x20000300, 0x20000100, 0, 0x200002c0);
+ NONFAILING(memcpy((void*)0x20000200, "./file0\000", 8));
+ NONFAILING(memcpy((void*)0x20000240, "security.capability\000", 20));
+ NONFAILING(*(uint32_t*)0x20000280 = 0x3000000);
+ NONFAILING(*(uint32_t*)0x20000284 = 0);
+ NONFAILING(*(uint32_t*)0x20000288 = 0);
+ NONFAILING(*(uint32_t*)0x2000028c = 0);
+ NONFAILING(*(uint32_t*)0x20000290 = 0);
+ NONFAILING(*(uint32_t*)0x20000294 = 0);
+ syscall(__NR_lsetxattr, 0x20000200, 0x20000240, 0x20000280, 0x18, 0);
+ NONFAILING(memcpy((void*)0x200000c0, "./file0\000", 8));
+ NONFAILING(memcpy(
+ (void*)0x200002c0,
+ "security.capability\000\311\2750\022\230>\002\025Y`\031j*\204X_"
+ "\031\301\310&\027)"
+ "\202\250\336\034\314L\334i\207\377\311q\\\357\"\316\344\306s\3248\215^"
+ "V\004\240\2708\257\263["
+ "\323R\344\311\356d\232w\022\b0\234\2446\277\221\237\331ck\372%_"
+ "\364\263\037@\370\216\314\234-\201!q\304\022bO\f\024/"
+ "\305Oe\364\2229\362v\206\301}H\236\222]\241\233\363\0360\354u\315\222#"
+ "yWf\034\350\241V\204\030\346\323\324(\027O\211\241\034\310!"
+ "\373\366A\"\243okA\034",
+ 169));
+ inject_fault(7);
+ syscall(__NR_getxattr, 0x200000c0, 0x200002c0, 0, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_binfmt_misc();
+ setup_leak();
+ setup_fault();
+ install_segv_handler();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/66ab7d59ba4e2b4d7cb27ea0561db6eeaf272b61.c b/syzkaller-repros/linux/66ab7d59ba4e2b4d7cb27ea0561db6eeaf272b61.c
new file mode 100644
index 0000000..4dec97e
--- /dev/null
+++ b/syzkaller-repros/linux/66ab7d59ba4e2b4d7cb27ea0561db6eeaf272b61.c
@@ -0,0 +1,900 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/loop.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ exit(1);
+ }
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+struct fs_image_segment {
+ void* data;
+ uintptr_t size;
+ uintptr_t offset;
+};
+
+#define IMAGE_MAX_SEGMENTS 4096
+#define IMAGE_MAX_SIZE (129 << 20)
+
+#define sys_memfd_create 319
+
+static unsigned long fs_image_segment_check(unsigned long size,
+ unsigned long nsegs, long segments)
+{
+ unsigned long i;
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ if (nsegs > IMAGE_MAX_SEGMENTS)
+ nsegs = IMAGE_MAX_SEGMENTS;
+ for (i = 0; i < nsegs; i++) {
+ if (segs[i].size > IMAGE_MAX_SIZE)
+ segs[i].size = IMAGE_MAX_SIZE;
+ segs[i].offset %= IMAGE_MAX_SIZE;
+ if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
+ segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
+ if (size < segs[i].offset + segs[i].offset)
+ size = segs[i].offset + segs[i].offset;
+ }
+ if (size > IMAGE_MAX_SIZE)
+ size = IMAGE_MAX_SIZE;
+ return size;
+}
+
+static long syz_read_part_table(volatile unsigned long size,
+ volatile unsigned long nsegs,
+ volatile long segments)
+{
+ char loopname[64], linkname[64];
+ int loopfd, err = 0, res = -1;
+ unsigned long i, j;
+ size = fs_image_segment_check(size, nsegs, segments);
+ int memfd = syscall(sys_memfd_create, "syz_read_part_table", 0);
+ if (memfd == -1) {
+ err = errno;
+ goto error;
+ }
+ if (ftruncate(memfd, size)) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ for (i = 0; i < nsegs; i++) {
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ int res1 = 0;
+ res1 = pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset);
+ if (res1 < 0) {
+ }
+ }
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
+ loopfd = open(loopname, O_RDWR);
+ if (loopfd == -1) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ if (errno != EBUSY) {
+ err = errno;
+ goto error_close_loop;
+ }
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ usleep(1000);
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ err = errno;
+ goto error_close_loop;
+ }
+ }
+ struct loop_info64 info;
+ if (ioctl(loopfd, LOOP_GET_STATUS64, &info)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ info.lo_flags |= LO_FLAGS_PARTSCAN;
+ if (ioctl(loopfd, LOOP_SET_STATUS64, &info)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ res = 0;
+ for (i = 1, j = 0; i < 8; i++) {
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llup%d", procid, (int)i);
+ struct stat statbuf;
+ if (stat(loopname, &statbuf) == 0) {
+ snprintf(linkname, sizeof(linkname), "./file%d", (int)j++);
+ if (symlink(loopname, linkname)) {
+ }
+ }
+ }
+error_clear_loop:
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+error_close_loop:
+ close(loopfd);
+error_close_memfd:
+ close(memfd);
+error:
+ errno = err;
+ return res;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 12; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+uint64_t r[1] = {0x0};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_getpid);
+ break;
+ case 1:
+ syscall(__NR_clone, 0x20002100ul, 0ul, 0x9999999999999999ul, 0ul, -1ul);
+ break;
+ case 2:
+ syscall(__NR_perf_event_open, 0ul, 0, 0ul, -1, 0ul);
+ break;
+ case 3:
+ syscall(__NR_socket, 2ul, 0x4000000805ul, 0);
+ break;
+ case 4:
+ syscall(__NR_socket, 2ul, 5ul, 0x84ul);
+ break;
+ case 5:
+ res = syscall(__NR_stat, 0ul, 0x20000300ul);
+ if (res != -1)
+ r[0] = *(uint32_t*)0x2000031c;
+ break;
+ case 6:
+ syscall(__NR_setgid, r[0]);
+ break;
+ case 7:
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0ul, 0ul);
+ break;
+ case 8:
+ syscall(__NR_dup2, -1, -1);
+ break;
+ case 9:
+ *(uint16_t*)0x20000280 = 0xa;
+ *(uint16_t*)0x20000282 = htobe16(0);
+ *(uint32_t*)0x20000284 = htobe32(0);
+ *(uint8_t*)0x20000288 = 0xfe;
+ *(uint8_t*)0x20000289 = 0x80;
+ *(uint8_t*)0x2000028a = 0;
+ *(uint8_t*)0x2000028b = 0;
+ *(uint8_t*)0x2000028c = 0;
+ *(uint8_t*)0x2000028d = 0;
+ *(uint8_t*)0x2000028e = 0;
+ *(uint8_t*)0x2000028f = 0;
+ *(uint8_t*)0x20000290 = 0;
+ *(uint8_t*)0x20000291 = 0;
+ *(uint8_t*)0x20000292 = 0;
+ *(uint8_t*)0x20000293 = 0;
+ *(uint8_t*)0x20000294 = 0;
+ *(uint8_t*)0x20000295 = 0;
+ *(uint8_t*)0x20000296 = 0;
+ *(uint8_t*)0x20000297 = 0xbb;
+ *(uint32_t*)0x20000298 = 0;
+ *(uint16_t*)0x2000029c = 0xa;
+ *(uint16_t*)0x2000029e = htobe16(0);
+ *(uint32_t*)0x200002a0 = htobe32(0);
+ *(uint8_t*)0x200002a4 = -1;
+ *(uint8_t*)0x200002a5 = 1;
+ *(uint8_t*)0x200002a6 = 0;
+ *(uint8_t*)0x200002a7 = 0;
+ *(uint8_t*)0x200002a8 = 0;
+ *(uint8_t*)0x200002a9 = 0;
+ *(uint8_t*)0x200002aa = 0;
+ *(uint8_t*)0x200002ab = 0;
+ *(uint8_t*)0x200002ac = 0;
+ *(uint8_t*)0x200002ad = 0;
+ *(uint8_t*)0x200002ae = 0;
+ *(uint8_t*)0x200002af = 0;
+ *(uint8_t*)0x200002b0 = 0;
+ *(uint8_t*)0x200002b1 = 0;
+ *(uint8_t*)0x200002b2 = 0;
+ *(uint8_t*)0x200002b3 = 1;
+ *(uint32_t*)0x200002b4 = 0;
+ *(uint16_t*)0x200002b8 = 0;
+ *(uint32_t*)0x200002bc = 0;
+ *(uint32_t*)0x200002c0 = 0;
+ *(uint32_t*)0x200002c4 = 0;
+ *(uint32_t*)0x200002c8 = 0;
+ *(uint32_t*)0x200002cc = 0;
+ *(uint32_t*)0x200002d0 = 0;
+ *(uint32_t*)0x200002d4 = 0;
+ *(uint32_t*)0x200002d8 = 0;
+ syscall(__NR_setsockopt, -1, 0x29ul, 0xccul, 0x20000280ul, 0x5cul);
+ break;
+ case 10:
+ *(uint64_t*)0x20000040 = 0x80;
+ *(uint64_t*)0x20000048 = 0xef;
+ syscall(__NR_ioctl, -1, 0x127ful, 0x20000040ul);
+ break;
+ case 11:
+ syz_read_part_table(0x400, 0, 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/67748d865de4a2d605805e74d2c16adc6d7bf8ed.c b/syzkaller-repros/linux/67748d865de4a2d605805e74d2c16adc6d7bf8ed.c
new file mode 100644
index 0000000..ede8658
--- /dev/null
+++ b/syzkaller-repros/linux/67748d865de4a2d605805e74d2c16adc6d7bf8ed.c
@@ -0,0 +1,319 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000200 = 0x20000000;
+ *(uint16_t*)0x20000000 = 0x10;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x20000208 = 0xc;
+ *(uint64_t*)0x20000210 = 0x20000040;
+ *(uint64_t*)0x20000040 = 0x20000440;
+ memcpy(
+ (void*)0x20000440,
+ "\xfc\x00\x00\x00\x03\x08\x01\x00\x2d\xbd\x70\x00\xff\xdb\xdf\xd0\x03\x00"
+ "\x00\x02\x0c\x00\x01\x00\x73\x79\x7a\x31\x00\x00\x00\x00\x08\x00\x03\x00"
+ "\xe0\xff\xff\x06\x08\x00\x06\x00\x00\x00\x00\x00\x0c\x00\x04\x00\x08\x00"
+ "\x05\x00\x00\x00\x80\x01\x08\x00\x03\x00\x21\x00\x03\xff\xa0\x00\x02\x00"
+ "\x08\x00\x03\x00\x00\x01\x00\x00\x08\x00\x03\x00\x00\x00\x00\x00\x08\x00"
+ "\x03\x00\x00\x00\x00\x00\x21\xab\x3d\x7d\x43\xca\xfe\xc0\x9f\x91\x99\x9e"
+ "\x58\x14\x21\x21\x72\x4d\xc7\xca\x1f\xac\x72\x8e\x14\x00\x04\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x08\x00\x03\x00"
+ "\x00\x00\x00\x00\x14\x00\x01\x00\x08\x00\x01\x00\xac\x1e\x00\x01\x08\x00"
+ "\x02\x00\x7f\x00\x00\x01\x14\x00\x01\x00\x08\x00\x01\x00\xac\x1e\x01\x01"
+ "\x08\x00\x02\x00\xff\xff\xff\xff\x08\x00\x03\x00\x00\x04\x00\x00\x0c\x00"
+ "\x02\x00\x08\x00\x01\x00\x3a\x00\x00\x00\x14\x00\x01\x00\x08\x00\x01\x00"
+ "\xac\x1e\x01\x01\x08\x00\x02\x00\xe0\x00\x00\x02\x08\x1c\x06\x00\x00\x00"
+ "\x00\x00\x08\x00\x86\x00\x00\x00\x00\x01\x08\x00\x05\x00\x00\x00\x00\x15"
+ "\xeb\xf4\xac\xa3\x58\xd0\xe9\xf8\x14\x89\x08\xa2\x80\x50\x2a\xb7\x18\x0d"
+ "\x54\x5a\x75\xd3\x82\xcd\x56\x52\x37\x17\xe6\x25\x76\x3b\xff\xe7\x69\x44"
+ "\x66\xce\xa0\x75\xf9\x0d\xa3\xb2\xd1\x7a\x3a\x52\x0d\xb0\xdd\xb9\xa3\x94"
+ "\x28\x24\x4b\x4c\x62\x6e\x12\x24\x7f\xba\xfa\xd4\x08\xaa\xdc\x5b\xf3\xce"
+ "\x45\x73\x23\x32\xee\x95\x76\x59\xaf\x6e\xfb\x4a\x58\x36\x76\xec\x71\xe4"
+ "\xee\x51\x6e\x68\x9d\x37\x56\x06\xd1\x17\x9f\x22\xf5\x69\xb6\x7c\x4b\x47"
+ "\x87\x4a\x14\xca\x1b\xed\xd4\xc2\x8f\xde\x9b\x28\x96\xc9\x0e\xd8\xac\xaa"
+ "\xcc\x50\xb1\xba\x79\xa2\x7c\xe2\xf8\x6f\x33\x56\xd9\xda\xb1\xec\x5a\xe7"
+ "\xb7\x1c\x64\xe5\x42\xc4\x57\x85\x7f\xb2\xdd\x53\xc5\xe1\xfc\x9b\xde\xf0"
+ "\x07\xdb\xe5\xfb\x55\xe0\x72\x3f\x4f\x44\xf0\x97\x1d\xf3\x24\xbf\x3e\x00"
+ "\x51\x35\xf4\x4e\xc0\x1c\xf1\x19\xc7\x31\x40\x22\x82\x5c\xfe\xfc\xca\x63"
+ "\xda\xbc\x87\xc8\x2d\xe5\xc6\x5a\x09\xeb\x9e\xee\xf2\xc8\xa9\xb2\x1d\x9e"
+ "\xd0\x64\x61\xdc\x21\xec\xd2\xc2\x15\x70\x53\x9e\x60\x20\x75\x68\x02\xdd"
+ "\x0f\x04\x61\xb4\xcf\x7d\xdb",
+ 493);
+ *(uint64_t*)0x20000048 = 0xfc;
+ *(uint64_t*)0x20000218 = 1;
+ *(uint64_t*)0x20000220 = 0;
+ *(uint64_t*)0x20000228 = 0;
+ *(uint32_t*)0x20000230 = 0x4000000;
+ syscall(__NR_sendmsg, r[0], 0x20000200ul, 0x940ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/679c09d7d8ae7850343c817c27bde5d9bd20d981.c b/syzkaller-repros/linux/679c09d7d8ae7850343c817c27bde5d9bd20d981.c
new file mode 100644
index 0000000..a60e61e
--- /dev/null
+++ b/syzkaller-repros/linux/679c09d7d8ae7850343c817c27bde5d9bd20d981.c
@@ -0,0 +1,294 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000040, "/dev/ttyS3\000", 11);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000080 = 0xa;
+ *(uint32_t*)0x20000084 = 0x400000;
+ *(uint32_t*)0x20000088 = 0x100;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 0x400000;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0x80000;
+ *(uint32_t*)0x200000a0 = 0x200ff;
+ *(uint8_t*)0x200000a4 = 0;
+ *(uint8_t*)0x200000a5 = 0x41;
+ *(uint32_t*)0x200000a8 = 3;
+ *(uint16_t*)0x200000ac = 0;
+ *(uint16_t*)0x200000ae = 0x7c5;
+ *(uint64_t*)0x200000b0 = 0;
+ *(uint16_t*)0x200000b8 = 0;
+ *(uint32_t*)0x200000bc = 0;
+ *(uint64_t*)0x200000c0 = 0;
+ syscall(__NR_ioctl, r[0], 0x541ful, 0x20000080ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/68019ecadea1dc5071dccdd4450e9fb378c45f05.c b/syzkaller-repros/linux/68019ecadea1dc5071dccdd4450e9fb378c45f05.c
new file mode 100644
index 0000000..59275c4
--- /dev/null
+++ b/syzkaller-repros/linux/68019ecadea1dc5071dccdd4450e9fb378c45f05.c
@@ -0,0 +1,453 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000100, "\xf3", 1);
+ inject_fault(22);
+ syscall(__NR_ioctl, r[0], 0x4b61ul, 0x20000100ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/684acfc05e01c6b53ea2b2034758dac4c39f9ac8.c b/syzkaller-repros/linux/684acfc05e01c6b53ea2b2034758dac4c39f9ac8.c
new file mode 100644
index 0000000..1610103
--- /dev/null
+++ b/syzkaller-repros/linux/684acfc05e01c6b53ea2b2034758dac4c39f9ac8.c
@@ -0,0 +1,1031 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 16; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_connect, -1, 0ul, 0ul);
+ break;
+ case 1:
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint64_t*)0x200001d0 = 0;
+ *(uint64_t*)0x200001d8 = 8;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001f0 = 0;
+ syscall(__NR_sendmsg, -1, 0x200001c0ul, 0ul);
+ break;
+ case 2:
+ res = syscall(__NR_socket, 2ul, 1ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 3:
+ *(uint32_t*)0x20000040 = 1;
+ syscall(__NR_setsockopt, r[0], 6ul, 0x210000000013ul, 0x20000040ul, 4ul);
+ break;
+ case 4:
+ *(uint16_t*)0x20000080 = 2;
+ *(uint16_t*)0x20000082 = htobe16(0x4e21);
+ *(uint8_t*)0x20000084 = 0xac;
+ *(uint8_t*)0x20000085 = 0x14;
+ *(uint8_t*)0x20000086 = 0x14;
+ *(uint8_t*)0x20000087 = 0xaa;
+ syscall(__NR_bind, r[0], 0x20000080ul, 0x10ul);
+ break;
+ case 5:
+ *(uint16_t*)0x20000180 = 2;
+ *(uint16_t*)0x20000182 = htobe16(0x4e21);
+ *(uint8_t*)0x20000184 = 0xac;
+ *(uint8_t*)0x20000185 = 0x14;
+ *(uint8_t*)0x20000186 = 0x14;
+ *(uint8_t*)0x20000187 = 0xaa;
+ syscall(__NR_connect, r[0], 0x20000180ul, 0x10ul);
+ break;
+ case 6:
+ memcpy((void*)0x20000240,
+ "\xac\x1e\x13\x01\xac\x1e\x00\x01\x03\x00\x00\x00\x04\x00\x00\x00"
+ "\xac\x1e\x00\x01",
+ 20);
+ syscall(__NR_setsockopt, -1, 0ul, 0x29ul, 0x20000240ul, 0x14ul);
+ break;
+ case 7:
+ res = syscall(__NR_socket, 2ul, 0x4000000000000001ul, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 8:
+ *(uint16_t*)0x20000280 = 2;
+ *(uint16_t*)0x20000282 = htobe16(0x4e23);
+ *(uint32_t*)0x20000284 = htobe32(0xe0000001);
+ syscall(__NR_bind, r[1], 0x20000280ul, 0x10ul);
+ break;
+ case 9:
+ *(uint16_t*)0x20000040 = 2;
+ *(uint16_t*)0x20000042 = htobe16(0x4e23);
+ *(uint32_t*)0x20000044 = htobe32(0);
+ syscall(__NR_sendto, r[1], 0ul, 0x74ul, 0x200087bdul, 0x20000040ul, 0x10ul);
+ break;
+ case 10:
+ memcpy((void*)0x20000000, "\f", 1);
+ syscall(__NR_sendto, r[1], 0x20000000ul, 0xfb386d1f6a4fd57dul, 0x400800aul,
+ 0ul, 0xae19fea218018fdul);
+ break;
+ case 11:
+ syscall(__NR_recvfrom, r[1], 0x20000080ul, 0xfffffffffffffe6aul, 0xf00ul,
+ 0ul, 0xb84608a41099d4b8ul);
+ break;
+ case 12:
+ syscall(__NR_setsockopt, r[0], 6ul, 0x16ul, 0x20000240ul, 0xb2ul);
+ break;
+ case 13:
+ *(uint32_t*)0x20000200 = 0;
+ syscall(__NR_setsockopt, r[0], 6ul, 0x13ul, 0x20000200ul, 0x88ul);
+ break;
+ case 14:
+ memcpy(
+ (void*)0x20000640,
+ "\xe0\x46\x38\x57\x38\xd0\xb6\xe2\xf1\x70\x50\xc3\x00\x2a\x9f\xe3\xe2"
+ "\xf4\xbb\xc2\x26\xe3\x9b\xf3\x52\x04\xd2\x75\xa8\xfa\xdd\xe3\x7a\xab"
+ "\x39\x05\xbb\xac\xaf\x04\xd5\x7f\xb2\x46\xd6\x60\xea\x69\xd7\x55\xb5"
+ "\xfa\x4e\x9d\xcd\xda\x99\x19\xe7\xcf\xdd\x2f\xd6\xf2\xff\xd8\xca\x8b"
+ "\x45\x0d\x8b\x06\x46\xe2\xd9\x36\x3d\x42\xc0\x96\xc6\x30\xe5\x7a\x2b"
+ "\xfd\x2c\x36\xce\xc6\x95\x82\x14\x37\xe9\xd3\x55\x4f\x3e\xb5\xc0\x48"
+ "\x23\x6b\x4b\x4a\xdb\x7e\x30\x2a\x15\x88\xfa\x2d\xaa\x01\x01\x00\x00"
+ "\x00\x00\x00\x00\xf3\x8f\xe3\xb4\xbd\xed\x81\x20\x7e\xfe\x8f\xd9\x87"
+ "\xbd\x3b\x2c\xc7\x6b\x79\xde\xb9\x6d\xf1\x3c\x54\x56\x63\x0d\x4c\xfb"
+ "\x85\x8f\x6d\xbc\xdd\x4f\x19\x9a\x51\x64\xba\x2f\xde\x00\x14\xd7\xf9"
+ "\x8d\x92\x51\xbb\xc0\x7b\xca\x2b\x67\x10\x30\x8d\xdd\xc5\x40\xdf\xb4"
+ "\x4b\x0f\x9a\x5f\x27\xd7\x3e\x1c\x33\xd0\x91\xce\x5c\x7f\x8e\x57\x29"
+ "\x11\x12\x23\x1b\x05\x1a\x2a\xf6\x34\xf3\x81\x20\x3b\x6b\x98\xcb\x0c"
+ "\x0a\x12\x91\xbd\x09\x4e\x86\x10\x61\xa5\xa7\xcd\x47\x77\xd4\x47\x69"
+ "\x0e\x4c\xe2\xc0\x7c\x13\xe8\xbe\x18\x01\x40\x70\x68\x13\x95\xd0\xb0"
+ "\xc3\x85\xe3\x9c\xe7\xd4\x22\x63\x72\x55\xc6\xd1\x32\x29\xf2\x80\xb5"
+ "\x70\x64\xba\x62\xd5\x2e\x7b\xfe\x69\x5f\x75\xde\x48\x54\xfd\xef\x56"
+ "\xf9\x3c\xa9\xd2\x37\x17\x5a\xa0\x19\x7b\x0e\x68\x50\xbd\x41\x58\x66"
+ "\x6d\x28\x00\x6d\xa6\xa3\x53\x62\xb2\x9e\xd6\x89\x55\x07\xab\x40\x64"
+ "\xc7\xfc\xec\xe1\x2d\xfb\x94\x11\xb1\x27\x40\x80\x91\x5c\x0d\x3a\x12"
+ "\x4a\xe1\xb7\x7b\xe2\xd7\xc8\xc9\xc8\x6c\x4d\x7a\x75\x89\xd7\xfc\x9c"
+ "\x92\x2a\xc8\x4b\x41\x1d\x0c\x21\x98\x16\xf5\x86\xb6\xfc\x7d\x24\x52"
+ "\xff\x4c\x5e\xb6\x4f\x91\x35\x98\x96\x8c\xfa\xe6\xf3\x0f\xb0\xdc\x0e"
+ "\xe0\x88\x65\x73\x9e\xd8\xae\xf2\x7a\x1d\x97\x38\x60\x53\x1a\xe8\xa8"
+ "\xc5\xdd\x62\x63\xe6\x90\xa5\xbe\x08\xe6\x73\x2a\x2d\x52\x6a\x64\x55"
+ "\xab\x9a\x9f\xcd\x36\x14\x04\x62\x02\x14\x16\xcc\x8d\x43\xc5\xb0\x92"
+ "\x15\xd8\xe4\xc2\x21\xea\x58\xfc\x69\x74\xed\xb8\xe2\x58\xc7\x38\x81"
+ "\x1f\x52\x3b\x25\xc3\xd9\x4c\x91\xb7\xd0\x80\xb5\x46\x6c\xbe\x69\x9b"
+ "\x21\x23\xca\xc0\x24\x30\xe0\x1d\x4b\x57\xc0\xdc\x79\x42\x68\xf9\xb1"
+ "\x72\x69\x47\x45\x67\x8f\xcc\x68\xc5\x69\xd0\x1e\x82\x11\x13\xd7\x6b"
+ "\x09\x0a\xc0\x74\x0c\xd3\x5f\x82\xbf\xc0\x27\xbf\xd5\x00\x90\x4b\xc6"
+ "\x2e\x26\x0d\xc9\xd6\x0d\x15\x45\x39\x61\x41\xcf\xf6\x1b\xf7\x20\xd5"
+ "\xaf\xf1\x8c\x58\x27\x8c\xc2\x77\x8e\xae\x68\xf3\xea\xd5\x3a\x4a\xda"
+ "\xe3\xb6\x8c\x53\x44\xc3\xa9\x82\x93\x9d\x84\x66\x1a\x04\x26\x22\xfc"
+ "\x94\x14\xee\x87\x3a\x78\x54\x82\x99\x34\x0d\x8f\xde\xf8\x79\x80\x2c"
+ "\x63\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 611);
+ syscall(__NR_sendto, r[0], 0x20000640ul, 0xffffffffffffff67ul, 0x40007bdul,
+ 0ul, 0xffffffffffffff4ful);
+ break;
+ case 15:
+ syscall(__NR_recvfrom, r[0], 0x200198c0ul, 0x19000ul, 0ul, 0ul, 0x3eul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/685cea42775bcc9dbb3e2465b643e2fb098e961d.c b/syzkaller-repros/linux/685cea42775bcc9dbb3e2465b643e2fb098e961d.c
new file mode 100644
index 0000000..765607a
--- /dev/null
+++ b/syzkaller-repros/linux/685cea42775bcc9dbb3e2465b643e2fb098e961d.c
@@ -0,0 +1,142 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+void execute_one(void)
+{
+ memcpy((void*)0x200001c0, "/dev/infiniband/rdma_cm\000", 24);
+ syscall(__NR_openat, 0xffffffffffffff9c, 0x200001c0, 2, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/699d00fe76ebc818fa6fb822b14ca79c0bf10ae4.c b/syzkaller-repros/linux/699d00fe76ebc818fa6fb822b14ca79c0bf10ae4.c
new file mode 100644
index 0000000..fd9a412
--- /dev/null
+++ b/syzkaller-repros/linux/699d00fe76ebc818fa6fb822b14ca79c0bf10ae4.c
@@ -0,0 +1,380 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ use_temporary_dir();
+ intptr_t res = 0;
+ res = syscall(__NR_pipe, 0x200000c0ul);
+ if (res != -1) {
+ r[0] = *(uint32_t*)0x200000c0;
+ r[1] = *(uint32_t*)0x200000c4;
+ }
+ syscall(__NR_write, r[1], 0x20000340ul, 0xff0eul);
+ syscall(__NR_close, r[1]);
+ res = syscall(__NR_socket, 0xaul, 1ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ *(uint32_t*)0x200000c0 = 1;
+ syscall(__NR_setsockopt, r[2], 6ul, 0x13ul, 0x200000c0ul, 4ul);
+ syscall(__NR_setsockopt, r[1], 6ul, 0xeul, 0ul, 0ul);
+ *(uint16_t*)0x20000140 = 0xa;
+ *(uint16_t*)0x20000142 = htobe16(0);
+ *(uint32_t*)0x20000144 = htobe32(0);
+ memcpy((void*)0x20000148,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
+ 16);
+ *(uint32_t*)0x20000158 = 0;
+ syscall(__NR_connect, r[2], 0x20000140ul, 0x1cul);
+ syscall(__NR_fcntl, -1, 0x10ul, 0ul);
+ memcpy((void*)0x20000040, "tls\000", 4);
+ syscall(__NR_setsockopt, r[2], 6ul, 0x1ful, 0x20000040ul, 0x355ul);
+ *(uint16_t*)0x200002c0 = 0x304;
+ *(uint16_t*)0x200002c2 = 0x35;
+ memcpy((void*)0x200002c4, "\x88\x13\xe9\xa0\xf4\x6c\x87\xfb", 8);
+ memcpy((void*)0x200002cc,
+ "\x70\x6e\x9e\xce\x30\x99\x6d\x32\x0a\xfd\x87\xd0\x0c\x28\xf8\x7c",
+ 16);
+ memcpy((void*)0x200002dc, "\x85\x72\xe9\xf5", 4);
+ memcpy((void*)0x200002e0, "\x1e\x99\x4c\x16\xc8\x29\x4e\x50", 8);
+ syscall(__NR_setsockopt, r[2], 0x11aul, 1ul, 0x200002c0ul, 0x28ul);
+ inject_fault(2);
+ syscall(__NR_splice, r[0], 0ul, r[1], 0ul, 0x100000000ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6ba1a7dced6ab743cf2068c4eb61286dbc50cd6f.c b/syzkaller-repros/linux/6ba1a7dced6ab743cf2068c4eb61286dbc50cd6f.c
new file mode 100644
index 0000000..9006fb2
--- /dev/null
+++ b/syzkaller-repros/linux/6ba1a7dced6ab743cf2068c4eb61286dbc50cd6f.c
@@ -0,0 +1,1874 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 15; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[5] = {0x0, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_ioctl, -1, 0x8903ul, 0x20000040ul);
+ if (res != -1)
+ NONFAILING(r[0] = *(uint32_t*)0x20000040);
+ break;
+ case 1:
+ NONFAILING(*(uint32_t*)0x20000080 = 0);
+ NONFAILING(*(uint32_t*)0x20000084 = 0x70);
+ NONFAILING(*(uint8_t*)0x20000088 = 0);
+ NONFAILING(*(uint8_t*)0x20000089 = 0);
+ NONFAILING(*(uint8_t*)0x2000008a = 0);
+ NONFAILING(*(uint8_t*)0x2000008b = 0);
+ NONFAILING(*(uint32_t*)0x2000008c = 0);
+ NONFAILING(*(uint64_t*)0x20000090 = 0x7fff);
+ NONFAILING(*(uint64_t*)0x20000098 = 0);
+ NONFAILING(*(uint64_t*)0x200000a0 = 0);
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 0, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 1, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 2, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 3, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 4, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 5, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 6, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 7, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 8, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 9, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 10, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 11, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 12, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 13, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 14, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 15, 2));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 17, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 18, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 19, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 20, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 21, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 22, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 23, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 24, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 25, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 26, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 27, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 28, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200000a8, 0, 29, 35));
+ NONFAILING(*(uint32_t*)0x200000b0 = 0xfffffffc);
+ NONFAILING(*(uint32_t*)0x200000b4 = 0);
+ NONFAILING(*(uint64_t*)0x200000b8 = 0);
+ NONFAILING(*(uint64_t*)0x200000c0 = 0);
+ NONFAILING(*(uint64_t*)0x200000c8 = 0);
+ NONFAILING(*(uint64_t*)0x200000d0 = 0);
+ NONFAILING(*(uint32_t*)0x200000d8 = 0);
+ NONFAILING(*(uint32_t*)0x200000dc = 0);
+ NONFAILING(*(uint64_t*)0x200000e0 = 0);
+ NONFAILING(*(uint32_t*)0x200000e8 = 0);
+ NONFAILING(*(uint16_t*)0x200000ec = 0);
+ NONFAILING(*(uint16_t*)0x200000ee = 0);
+ res = syscall(__NR_perf_event_open, 0x20000080ul, r[0], -1ul, -1, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ NONFAILING(*(uint32_t*)0x20000280 = 2);
+ NONFAILING(*(uint32_t*)0x20000284 = 0x70);
+ NONFAILING(*(uint8_t*)0x20000288 = 0x20);
+ NONFAILING(*(uint8_t*)0x20000289 = 0x1f);
+ NONFAILING(*(uint8_t*)0x2000028a = 0);
+ NONFAILING(*(uint8_t*)0x2000028b = 2);
+ NONFAILING(*(uint32_t*)0x2000028c = 0);
+ NONFAILING(*(uint64_t*)0x20000290 = 0x80);
+ NONFAILING(*(uint64_t*)0x20000298 = 0x1204);
+ NONFAILING(*(uint64_t*)0x200002a0 = 0xa);
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 0, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 1, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 2, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 3, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 4, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 5, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 6, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 7, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 8, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 9, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 10, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 11, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 12, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 13, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 14, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 15, 2));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 17, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 18, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 19, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 20, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 21, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 22, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 23, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 24, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 25, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 26, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 1, 27, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 28, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200002a8, 0, 29, 35));
+ NONFAILING(*(uint32_t*)0x200002b0 = 4);
+ NONFAILING(*(uint32_t*)0x200002b4 = 2);
+ NONFAILING(*(uint64_t*)0x200002b8 = 0x20000000);
+ NONFAILING(*(uint64_t*)0x200002c0 = 8);
+ NONFAILING(*(uint64_t*)0x200002c8 = 0x20000);
+ NONFAILING(*(uint64_t*)0x200002d0 = 0x100);
+ NONFAILING(*(uint32_t*)0x200002d8 = 9);
+ NONFAILING(*(uint32_t*)0x200002dc = 7);
+ NONFAILING(*(uint64_t*)0x200002e0 = 0xcc3);
+ NONFAILING(*(uint32_t*)0x200002e8 = 0x1272);
+ NONFAILING(*(uint16_t*)0x200002ec = 0);
+ NONFAILING(*(uint16_t*)0x200002ee = 0);
+ syscall(__NR_ioctl, r[1], 0x4008240bul, 0x20000280ul);
+ break;
+ case 3:
+ NONFAILING(memcpy((void*)0x20000700, "./bus\000", 6));
+ res = syscall(__NR_creat, 0x20000700ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 4:
+ syscall(__NR_fsetxattr, -1, 0ul, 0ul, 0ul, 1ul);
+ break;
+ case 5:
+ syscall(__NR_ftruncate, r[2], 0x1000ul);
+ break;
+ case 6:
+ syscall(__NR_lseek, r[2], 0ul, 2ul);
+ break;
+ case 7:
+ NONFAILING(memcpy((void*)0x20000100, "./bus\000", 6));
+ res = syscall(__NR_open, 0x20000100ul, 0x141042ul, 0ul);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 8:
+ syscall(__NR_getsockopt, -1, 0x29ul, 0x22ul, 0ul, 0ul);
+ break;
+ case 9:
+ NONFAILING(memcpy((void*)0x20000300, "/dev/ocfs2_control\000", 19));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000300ul, 0x101000ul,
+ 0ul);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 10:
+ NONFAILING(*(uint32_t*)0x20000340 = 0x5ed68f99);
+ syscall(__NR_setsockopt, r[4], 0x10ful, 0x81ul, 0x20000340ul, 4ul);
+ break;
+ case 11:
+ syscall(__NR_ioctl, r[2], 0x81009431ul, 0x20000140ul);
+ break;
+ case 12:
+ NONFAILING(memcpy((void*)0x20000240, "./bus\000", 6));
+ syscall(__NR_open, 0x20000240ul, 0x105000ul, 0ul);
+ break;
+ case 13:
+ syscall(__NR_ioctl, -1, 0x40049409ul, -1);
+ break;
+ case 14:
+ syscall(__NR_ftruncate, r[3], 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ install_segv_handler();
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6c8a755e7ac31a5dfbb699fe8d5da4c0bdab6ab1.c b/syzkaller-repros/linux/6c8a755e7ac31a5dfbb699fe8d5da4c0bdab6ab1.c
new file mode 100644
index 0000000..02c3fc7
--- /dev/null
+++ b/syzkaller-repros/linux/6c8a755e7ac31a5dfbb699fe8d5da4c0bdab6ab1.c
@@ -0,0 +1,55 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ long res = 0;
+ memcpy((void*)0x200006c0, "/dev/video#", 12);
+ res = syz_open_dev(0x200006c0, 6, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x200000c0 = 8;
+ *(uint32_t*)0x200000c4 = 2;
+ *(uint32_t*)0x200000c8 = 1;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint32_t*)0x200000d0 = 0;
+ syscall(__NR_ioctl, r[0], 0xc0145608, 0x200000c0);
+ *(uint32_t*)0x20000040 = 2;
+ syscall(__NR_ioctl, r[0], 0x40045612, 0x20000040);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6ca587f7c057c003d5aba08d470e22fa0047a1ee.c b/syzkaller-repros/linux/6ca587f7c057c003d5aba08d470e22fa0047a1ee.c
new file mode 100644
index 0000000..9a16af9
--- /dev/null
+++ b/syzkaller-repros/linux/6ca587f7c057c003d5aba08d470e22fa0047a1ee.c
@@ -0,0 +1,501 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 8; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ *(uint32_t*)0x200001c0 = 6;
+ *(uint16_t*)0x200001c4 = 0x118;
+ *(uint16_t*)0x200001c6 = 0xfa00;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint32_t*)0x200001cc = 0;
+ memcpy((void*)0x200001d0,
+ "\xb7\x9e\x28\x44\x14\xa8\xee\x60\x40\x37\xb3\xd1\xcc\x43\x33\xa5"
+ "\xa4\x56\xbb\x4c\x57\x1f\x0f\x69\x25\xeb\x44\x49\xb5\x84\x0c\x37"
+ "\xac\xa9\x9e\x4e\xe9\x5c\x12\xef\x24\x02\xf7\x9e\xd5\x6c\x67\x27"
+ "\x59\x45\xc0\x80\x0b\xa4\x96\x13\x77\x44\xb5\x99\x4a\x7b\x09\x3c"
+ "\x0f\x5e\x33\x17\x93\xee\x44\xf0\x7b\x8f\x37\xe5\x16\xaa\x1d\x0f"
+ "\x63\xb7\xdf\x40\xd8\x8f\x1f\xa4\x46\xdb\xfe\xa5\x8c\x05\xad\xd0"
+ "\xd0\x05\x40\x76\x13\xca\x61\x78\xaf\xd7\x1a\xd1\x47\x7f\x0d\xd1"
+ "\xee\x0e\x8d\xa5\x5e\x66\xa4\x03\xcb\x38\x3b\xe9\x01\xe7\xf7\x77"
+ "\x21\x0e\x72\xed\x01\x23\x83\x45\xe8\x18\xb6\x75\xcf\x43\x99\xd8"
+ "\x8b\x02\x3b\x49\xa7\x4b\x3d\x8c\x06\x8c\x71\x7c\x89\x02\x08\xdd"
+ "\x0f\x4e\x78\xe3\x76\x17\xbc\xc1\xf0\x2a\xc6\xa6\x12\xe6\x74\x21"
+ "\x3b\x54\xd1\x24\x6a\x6b\x0f\xbd\x24\x35\xa7\xe6\x2d\xef\x1e\x78"
+ "\x7c\x19\xf4\x4c\xec\x1a\xb4\xdf\x0d\xfa\x37\xbc\x1e\xdf\x9f\xd3"
+ "\x06\x41\x77\xc6\xca\xc5\xe1\xca\x4d\x40\xf0\x1c\xbe\xac\x6e\x5a"
+ "\x28\x2d\x9e\x9f\x7b\x28\xd5\xad\x1c\x04\x26\xc1\x68\x36\x85\x38"
+ "\xa9\x14\xb1\xed\x35\x82\x8c\xf2\xfa\x3a\xfd\xc4\xd7\x15\x47\x92",
+ 256);
+ *(uint8_t*)0x200002d0 = 0;
+ *(uint8_t*)0x200002d1 = 0;
+ *(uint8_t*)0x200002d2 = 0;
+ *(uint8_t*)0x200002d3 = 0;
+ *(uint8_t*)0x200002d4 = 0;
+ *(uint8_t*)0x200002d5 = 0;
+ *(uint8_t*)0x200002d6 = 0;
+ *(uint8_t*)0x200002d7 = 1;
+ *(uint32_t*)0x200002d8 = -1;
+ *(uint32_t*)0x200002dc = 0;
+ syscall(__NR_write, -1, 0x200001c0ul, 0x120ul);
+ break;
+ case 1:
+ memcpy((void*)0x20000180, "/dev/infiniband/rdma_cm\000", 24);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000180ul, 2ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ res = syscall(__NR_socket, 0x1eul, 2ul, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ *(uint64_t*)0x20000240 = 0x200000c0;
+ *(uint16_t*)0x200000c0 = 0x1e;
+ *(uint8_t*)0x200000c2 = 1;
+ *(uint8_t*)0x200000c3 = 0;
+ *(uint32_t*)0x200000c4 = 1;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 2;
+ *(uint32_t*)0x20000248 = 0x10;
+ *(uint64_t*)0x20000250 = 0;
+ *(uint64_t*)0x20000258 = 0;
+ *(uint64_t*)0x20000260 = 0;
+ *(uint64_t*)0x20000268 = 0;
+ *(uint32_t*)0x20000270 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000240ul, 0ul);
+ break;
+ case 4:
+ *(uint16_t*)0x20000300 = 0xa;
+ *(uint16_t*)0x20000302 = htobe16(0x4e24);
+ *(uint32_t*)0x20000304 = htobe32(0x805);
+ *(uint8_t*)0x20000308 = 0;
+ *(uint8_t*)0x20000309 = 0;
+ *(uint8_t*)0x2000030a = 0;
+ *(uint8_t*)0x2000030b = 0;
+ *(uint8_t*)0x2000030c = 0;
+ *(uint8_t*)0x2000030d = 0;
+ *(uint8_t*)0x2000030e = 0;
+ *(uint8_t*)0x2000030f = 0;
+ *(uint8_t*)0x20000310 = 0;
+ *(uint8_t*)0x20000311 = 0;
+ *(uint8_t*)0x20000312 = 0;
+ *(uint8_t*)0x20000313 = 0;
+ *(uint8_t*)0x20000314 = 0;
+ *(uint8_t*)0x20000315 = 0;
+ *(uint8_t*)0x20000316 = 0;
+ *(uint8_t*)0x20000317 = 0;
+ *(uint32_t*)0x20000318 = 2;
+ *(uint16_t*)0x2000031c = 2;
+ *(uint16_t*)0x2000031e = htobe16(0x4e24);
+ *(uint8_t*)0x20000320 = 0xac;
+ *(uint8_t*)0x20000321 = 0x14;
+ *(uint8_t*)0x20000322 = 0x14;
+ *(uint8_t*)0x20000323 = 0xaa;
+ *(uint16_t*)0x2000032c = 0xa;
+ *(uint16_t*)0x2000032e = htobe16(0x4e20);
+ *(uint32_t*)0x20000330 = htobe32(0);
+ *(uint8_t*)0x20000334 = 0xfe;
+ *(uint8_t*)0x20000335 = 0x80;
+ *(uint8_t*)0x20000336 = 0;
+ *(uint8_t*)0x20000337 = 0;
+ *(uint8_t*)0x20000338 = 0;
+ *(uint8_t*)0x20000339 = 0;
+ *(uint8_t*)0x2000033a = 0;
+ *(uint8_t*)0x2000033b = 0;
+ *(uint8_t*)0x2000033c = 0;
+ *(uint8_t*)0x2000033d = 0;
+ *(uint8_t*)0x2000033e = 0;
+ *(uint8_t*)0x2000033f = 0;
+ *(uint8_t*)0x20000340 = 0;
+ *(uint8_t*)0x20000341 = 0;
+ *(uint8_t*)0x20000342 = 0;
+ *(uint8_t*)0x20000343 = 0xbb;
+ *(uint32_t*)0x20000344 = 4;
+ *(uint16_t*)0x20000348 = 2;
+ *(uint16_t*)0x2000034a = htobe16(0x4e23);
+ *(uint8_t*)0x2000034c = 0xac;
+ *(uint8_t*)0x2000034d = 0x14;
+ *(uint8_t*)0x2000034e = 0x14;
+ *(uint8_t*)0x2000034f = 0xaa;
+ *(uint16_t*)0x20000358 = 0xa;
+ *(uint16_t*)0x2000035a = htobe16(0x4e21);
+ *(uint32_t*)0x2000035c = htobe32(2);
+ *(uint8_t*)0x20000360 = 0xfe;
+ *(uint8_t*)0x20000361 = 0x88;
+ *(uint8_t*)0x20000362 = 0;
+ *(uint8_t*)0x20000363 = 0;
+ *(uint8_t*)0x20000364 = 0;
+ *(uint8_t*)0x20000365 = 0;
+ *(uint8_t*)0x20000366 = 0;
+ *(uint8_t*)0x20000367 = 0;
+ *(uint8_t*)0x20000368 = 0;
+ *(uint8_t*)0x20000369 = 0;
+ *(uint8_t*)0x2000036a = 0;
+ *(uint8_t*)0x2000036b = 0;
+ *(uint8_t*)0x2000036c = 0;
+ *(uint8_t*)0x2000036d = 0;
+ *(uint8_t*)0x2000036e = 0;
+ *(uint8_t*)0x2000036f = 1;
+ *(uint32_t*)0x20000370 = 6;
+ *(uint16_t*)0x20000374 = 2;
+ *(uint16_t*)0x20000376 = htobe16(0x4e22);
+ *(uint32_t*)0x20000378 = htobe32(-1);
+ *(uint16_t*)0x20000384 = 2;
+ *(uint16_t*)0x20000386 = htobe16(0x4e22);
+ *(uint32_t*)0x20000388 = htobe32(-1);
+ *(uint16_t*)0x20000394 = 2;
+ *(uint16_t*)0x20000396 = htobe16(0x4e23);
+ *(uint32_t*)0x20000398 = htobe32(0);
+ *(uint16_t*)0x200003a4 = 2;
+ *(uint16_t*)0x200003a6 = htobe16(0x4e23);
+ *(uint32_t*)0x200003a8 = htobe32(0xe0000002);
+ *(uint16_t*)0x200003b4 = 0xa;
+ *(uint16_t*)0x200003b6 = htobe16(0x4e24);
+ *(uint32_t*)0x200003b8 = htobe32(3);
+ *(uint8_t*)0x200003bc = -1;
+ *(uint8_t*)0x200003bd = 1;
+ *(uint8_t*)0x200003be = 0;
+ *(uint8_t*)0x200003bf = 0;
+ *(uint8_t*)0x200003c0 = 0;
+ *(uint8_t*)0x200003c1 = 0;
+ *(uint8_t*)0x200003c2 = 0;
+ *(uint8_t*)0x200003c3 = 0;
+ *(uint8_t*)0x200003c4 = 0;
+ *(uint8_t*)0x200003c5 = 0;
+ *(uint8_t*)0x200003c6 = 0;
+ *(uint8_t*)0x200003c7 = 0;
+ *(uint8_t*)0x200003c8 = 0;
+ *(uint8_t*)0x200003c9 = 0;
+ *(uint8_t*)0x200003ca = 0;
+ *(uint8_t*)0x200003cb = 1;
+ *(uint32_t*)0x200003cc = 0;
+ syscall(__NR_setsockopt, r[1], 0x84ul, 0x64ul, 0x20000300ul, 0xd0ul);
+ break;
+ case 5:
+ *(uint32_t*)0x20000080 = 0;
+ *(uint16_t*)0x20000084 = 0x18;
+ *(uint16_t*)0x20000086 = 0xfa00;
+ *(uint64_t*)0x20000088 = 0;
+ *(uint64_t*)0x20000090 = 0x20000000;
+ *(uint16_t*)0x20000098 = 0x111;
+ *(uint8_t*)0x2000009a = 0;
+ *(uint8_t*)0x2000009b = 0;
+ *(uint8_t*)0x2000009c = 0;
+ *(uint8_t*)0x2000009d = 0;
+ *(uint8_t*)0x2000009e = 0;
+ *(uint8_t*)0x2000009f = 0;
+ res = syscall(__NR_write, r[0], 0x20000080ul, 0x20ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000000;
+ break;
+ case 6:
+ *(uint32_t*)0x200001c0 = 2;
+ *(uint16_t*)0x200001c4 = 0x28;
+ *(uint16_t*)0x200001c6 = 0xfa00;
+ *(uint64_t*)0x200001c8 = 0;
+ *(uint16_t*)0x200001d0 = 0xa;
+ *(uint16_t*)0x200001d2 = htobe16(0);
+ *(uint32_t*)0x200001d4 = htobe32(-1);
+ *(uint8_t*)0x200001d8 = -1;
+ *(uint8_t*)0x200001d9 = 1;
+ *(uint8_t*)0x200001da = 0;
+ *(uint8_t*)0x200001db = 0;
+ *(uint8_t*)0x200001dc = 0;
+ *(uint8_t*)0x200001dd = 0;
+ *(uint8_t*)0x200001de = 0;
+ *(uint8_t*)0x200001df = 0;
+ *(uint8_t*)0x200001e0 = 0;
+ *(uint8_t*)0x200001e1 = 0;
+ *(uint8_t*)0x200001e2 = 0;
+ *(uint8_t*)0x200001e3 = 0;
+ *(uint8_t*)0x200001e4 = 0;
+ *(uint8_t*)0x200001e5 = 0;
+ *(uint8_t*)0x200001e6 = 0;
+ *(uint8_t*)0x200001e7 = 1;
+ *(uint32_t*)0x200001e8 = 0xfffffffe;
+ *(uint32_t*)0x200001ec = r[2];
+ syscall(__NR_write, r[0], 0x200001c0ul, 0x30ul);
+ break;
+ case 7:
+ *(uint32_t*)0x20000140 = 7;
+ *(uint16_t*)0x20000144 = 8;
+ *(uint16_t*)0x20000146 = 0xfa00;
+ *(uint32_t*)0x20000148 = r[2];
+ *(uint32_t*)0x2000014c = 0;
+ syscall(__NR_write, r[0], 0x20000140ul, 0x10ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6e89ce80a10c14d6e832ef9b558bcd045825e05b.c b/syzkaller-repros/linux/6e89ce80a10c14d6e832ef9b558bcd045825e05b.c
new file mode 100644
index 0000000..786ffb5
--- /dev/null
+++ b/syzkaller-repros/linux/6e89ce80a10c14d6e832ef9b558bcd045825e05b.c
@@ -0,0 +1,297 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ if (res != -1)
+ r[1] = res;
+ *(uint32_t*)0x20000200 = 0x14;
+ res = syscall(__NR_getsockname, r[1], 0x20000100ul, 0x20000200ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000104;
+ *(uint64_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint64_t*)0x20000050 = 0x20000000;
+ *(uint64_t*)0x20000000 = 0x200004c0;
+ memcpy((void*)0x200004c0,
+ "\x48\x00\x00\x00\x10\x00\x05\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00",
+ 20);
+ *(uint32_t*)0x200004d4 = r[2];
+ memcpy((void*)0x200004d8,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x12\x00\x0c\x00\x01\x00\x76"
+ "\x65\x74\x68\x00\x00\x00\x00\x18\x00\x02\x00\x14\x00\x01\x00\x00\x00"
+ "\x00\x00",
+ 36);
+ *(uint32_t*)0x200004fc = 0;
+ memcpy((void*)0x20000500,
+ "\x00\x00\x00\x00\x00\x84\x33\xdf\x6d\x6f\x6b\x57\x7d\x4e\xaa\xf2\x00"
+ "\x00\x07",
+ 19);
+ *(uint64_t*)0x20000008 = 0x48;
+ *(uint64_t*)0x20000058 = 1;
+ *(uint64_t*)0x20000060 = 0;
+ *(uint64_t*)0x20000068 = 0;
+ *(uint32_t*)0x20000070 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000040ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6ea7a0d0da1c0753938590eb42022ac3066ea3f0.c b/syzkaller-repros/linux/6ea7a0d0da1c0753938590eb42022ac3066ea3f0.c
new file mode 100644
index 0000000..79d1abc
--- /dev/null
+++ b/syzkaller-repros/linux/6ea7a0d0da1c0753938590eb42022ac3066ea3f0.c
@@ -0,0 +1,546 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 6; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_eventfd2, 0, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ res = syscall(__NR_dup, r[0]);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ *(uint32_t*)0x20000100 = 0;
+ *(uint16_t*)0x20000104 = 0x29da;
+ *(uint16_t*)0x20000106 = 0xfa00;
+ *(uint64_t*)0x20000108 = 0;
+ *(uint64_t*)0x20000110 = 0;
+ *(uint16_t*)0x20000118 = 0;
+ *(uint8_t*)0x2000011a = 0;
+ *(uint8_t*)0x2000011b = 0;
+ *(uint8_t*)0x2000011c = 0;
+ *(uint8_t*)0x2000011d = 0;
+ *(uint8_t*)0x2000011e = 0;
+ *(uint8_t*)0x2000011f = 0;
+ syscall(__NR_write, r[1], 0x20000100ul, 0x20ul);
+ break;
+ case 3:
+ memcpy((void*)0x20000080, "./bus\000", 6);
+ res = syscall(__NR_open, 0x20000080ul, 0x141042ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 4:
+ memcpy((void*)0x20000000, "./file0\000", 8);
+ memcpy((void*)0x20000040, "9p\000", 3);
+ memcpy((void*)0x200001c0, "trans=fd,", 9);
+ memcpy((void*)0x200001c9, "rfdno", 5);
+ *(uint8_t*)0x200001ce = 0x3d;
+ sprintf((char*)0x200001cf, "0x%016llx", (long long)r[2]);
+ *(uint8_t*)0x200001e1 = 0x2c;
+ memcpy((void*)0x200001e2, "wfdno", 5);
+ *(uint8_t*)0x200001e7 = 0x3d;
+ sprintf((char*)0x200001e8, "0x%016llx", (long long)r[0]);
+ *(uint8_t*)0x200001fa = 0x2c;
+ memcpy((void*)0x200001fb, "cache=none", 10);
+ *(uint8_t*)0x20000205 = 0x2c;
+ memcpy((void*)0x20000206, "access=client", 13);
+ *(uint8_t*)0x20000213 = 0x2c;
+ memcpy((void*)0x20000214, "debug", 5);
+ *(uint8_t*)0x20000219 = 0x3d;
+ sprintf((char*)0x2000021a, "0x%016llx", (long long)0xce);
+ *(uint8_t*)0x2000022c = 0x2c;
+ memcpy((void*)0x2000022d, "nodevmap", 8);
+ *(uint8_t*)0x20000235 = 0x2c;
+ memcpy((void*)0x20000236, "subj_role", 9);
+ *(uint8_t*)0x2000023f = 0x3d;
+ memcpy((void*)0x20000240, "eth1", 4);
+ *(uint8_t*)0x20000244 = 0x2c;
+ memcpy((void*)0x20000245, "subj_user", 9);
+ *(uint8_t*)0x2000024e = 0x3d;
+ memcpy((void*)0x2000024f, "%(+/(em0!", 9);
+ *(uint8_t*)0x20000258 = 0x2c;
+ memcpy((void*)0x20000259, "fsname", 6);
+ *(uint8_t*)0x2000025f = 0x3d;
+ memcpy((void*)0x20000260, "vmnet0cgroup)++-($", 18);
+ *(uint8_t*)0x20000272 = 0x2c;
+ memcpy((void*)0x20000273, "fsuuid", 6);
+ *(uint8_t*)0x20000279 = 0x3d;
+ *(uint8_t*)0x2000027a = 0x36;
+ *(uint8_t*)0x2000027b = 0xc6;
+ *(uint8_t*)0x2000027c = 0x37;
+ *(uint8_t*)0x2000027d = 0x30;
+ *(uint8_t*)0x2000027e = 0x36;
+ *(uint8_t*)0x2000027f = 0x38;
+ *(uint8_t*)0x20000280 = 0x61;
+ *(uint8_t*)0x20000281 = 0x33;
+ *(uint8_t*)0x20000282 = 0x2d;
+ *(uint8_t*)0x20000283 = 0x31;
+ *(uint8_t*)0x20000284 = 4;
+ *(uint8_t*)0x20000285 = 0x38;
+ *(uint8_t*)0x20000286 = 0x32;
+ *(uint8_t*)0x20000287 = 0x2d;
+ *(uint8_t*)0x20000288 = 0x31;
+ *(uint8_t*)0x20000289 = 0x39;
+ *(uint8_t*)0x2000028a = 0x37;
+ *(uint8_t*)0x2000028b = 0x32;
+ *(uint8_t*)0x2000028c = 0x2d;
+ *(uint8_t*)0x2000028d = 0x65;
+ *(uint8_t*)0x2000028e = 0x30;
+ *(uint8_t*)0x2000028f = 0x66;
+ *(uint8_t*)0x20000290 = 0x78;
+ *(uint8_t*)0x20000291 = 0x2d;
+ *(uint8_t*)0x20000292 = 0x62;
+ *(uint8_t*)0x20000293 = 0x38;
+ *(uint8_t*)0x20000294 = 0x39;
+ *(uint8_t*)0x20000295 = 0x64;
+ *(uint8_t*)0x20000296 = 0x48;
+ *(uint8_t*)0x20000297 = 0x34;
+ *(uint8_t*)0x20000298 = 0x38;
+ *(uint8_t*)0x20000299 = 0x31;
+ *(uint8_t*)0x2000029a = 0x2c;
+ memcpy((void*)0x2000029b, "pcr", 3);
+ *(uint8_t*)0x2000029e = 0x3d;
+ sprintf((char*)0x2000029f, "%020llu", (long long)0x32);
+ *(uint8_t*)0x200002b3 = 0x2c;
+ memcpy((void*)0x200002b4, "appraise", 8);
+ *(uint8_t*)0x200002bc = 0x2c;
+ memcpy((void*)0x200002bd, "defcontext", 10);
+ *(uint8_t*)0x200002c7 = 0x3d;
+ memcpy((void*)0x200002c8, "root", 4);
+ *(uint8_t*)0x200002cc = 0x2c;
+ memcpy((void*)0x200002cd, "fsmagic", 7);
+ *(uint8_t*)0x200002d4 = 0x3d;
+ sprintf((char*)0x200002d5, "0x%016llx", (long long)1);
+ *(uint8_t*)0x200002e7 = 0x2c;
+ *(uint8_t*)0x200002e8 = 0;
+ syscall(__NR_mount, 0ul, 0x20000000ul, 0x20000040ul, 0x2000000ul,
+ 0x200001c0ul);
+ break;
+ case 5:
+ memcpy((void*)0x200000c0, "./file0\000", 8);
+ syscall(__NR_open, 0x200000c0ul, 0x220141042ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6f26ec1b91269a365ebc62728c35e83fc8fcb1ad.c b/syzkaller-repros/linux/6f26ec1b91269a365ebc62728c35e83fc8fcb1ad.c
new file mode 100644
index 0000000..d62fb3e
--- /dev/null
+++ b/syzkaller-repros/linux/6f26ec1b91269a365ebc62728c35e83fc8fcb1ad.c
@@ -0,0 +1,1127 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x200009c0, "\316\217*\367\000\000\000\000\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200009c0ul,
+ 0x67514c7366170adeul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000100, "\354\333\000\000\000\000\000\000\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000100ul, 0x42ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000080, "\000", 1);
+ syscall(__NR_write, r[1], 0x20000080ul, 1ul);
+ memcpy((void*)0x20000a00, " ", 1);
+ syscall(__NR_write, r[0], 0x20000a00ul, 1ul);
+ *(uint16_t*)0x200000c0 = 0;
+ *(uint16_t*)0x200000c2 = 0;
+ *(uint64_t*)0x200000c8 = 0x8000000000;
+ *(uint64_t*)0x200000d0 = 0x82e2;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ *(uint32_t*)0x200000e0 = 0;
+ *(uint32_t*)0x200000e4 = 0;
+ *(uint32_t*)0x200000e8 = 0;
+ *(uint32_t*)0x200000ec = 0;
+ syscall(__NR_ioctl, r[1], 0x40305828ul, 0x200000c0ul);
+ *(uint32_t*)0x20000000 = 0x1000000;
+ *(uint32_t*)0x20000004 = r[0];
+ *(uint64_t*)0x20000008 = 0x8000000;
+ *(uint64_t*)0x20000010 = 0;
+ *(uint64_t*)0x20000018 = 0;
+ *(uint64_t*)0x20000020 = 0;
+ inject_fault(21);
+ syscall(__NR_ioctl, r[1], 0xc028660ful, 0x20000000ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/6f63dd43a3128aad6ccc78b0fdac97d714dae9ec.c b/syzkaller-repros/linux/6f63dd43a3128aad6ccc78b0fdac97d714dae9ec.c
new file mode 100644
index 0000000..498d65b
--- /dev/null
+++ b/syzkaller-repros/linux/6f63dd43a3128aad6ccc78b0fdac97d714dae9ec.c
@@ -0,0 +1,125 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint64_t*)0x20000010 = 0x20000080;
+ *(uint64_t*)0x20000080 = 0x20000f80;
+ *(uint32_t*)0x20000f80 = 0x58;
+ *(uint8_t*)0x20000f84 = 2;
+ *(uint8_t*)0x20000f85 = 6;
+ *(uint16_t*)0x20000f86 = 1;
+ *(uint32_t*)0x20000f88 = 0;
+ *(uint32_t*)0x20000f8c = 0;
+ *(uint8_t*)0x20000f90 = 0;
+ *(uint8_t*)0x20000f91 = 0;
+ *(uint16_t*)0x20000f92 = htobe16(0);
+ *(uint16_t*)0x20000f94 = 0x12;
+ *(uint16_t*)0x20000f96 = 3;
+ memcpy((void*)0x20000f98, "hash:net,port\000", 14);
+ *(uint16_t*)0x20000fa8 = 5;
+ *(uint16_t*)0x20000faa = 4;
+ *(uint8_t*)0x20000fac = 0;
+ *(uint16_t*)0x20000fb0 = 9;
+ *(uint16_t*)0x20000fb2 = 2;
+ memcpy((void*)0x20000fb4, "syz0\000", 5);
+ *(uint16_t*)0x20000fbc = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000fbe, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000fbf, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000fbf, 1, 7, 1);
+ *(uint16_t*)0x20000fc0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000fc2, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000fc3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000fc3, 0, 7, 1);
+ *(uint32_t*)0x20000fc4 = htobe32(0);
+ *(uint16_t*)0x20000fc8 = 5;
+ *(uint16_t*)0x20000fca = 5;
+ *(uint8_t*)0x20000fcc = 2;
+ *(uint16_t*)0x20000fd0 = 5;
+ *(uint16_t*)0x20000fd2 = 1;
+ *(uint8_t*)0x20000fd4 = 7;
+ *(uint64_t*)0x20000088 = 0x58;
+ *(uint64_t*)0x20000018 = 1;
+ *(uint64_t*)0x20000020 = 0;
+ *(uint64_t*)0x20000028 = 0;
+ *(uint32_t*)0x20000030 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000000ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0x20000140;
+ *(uint64_t*)0x20000140 = 0x20000080;
+ *(uint32_t*)0x20000080 = 0x4c;
+ *(uint8_t*)0x20000084 = 0xb;
+ *(uint8_t*)0x20000085 = 6;
+ *(uint16_t*)0x20000086 = 1;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint8_t*)0x20000090 = 0;
+ *(uint8_t*)0x20000091 = 0;
+ *(uint16_t*)0x20000092 = htobe16(0);
+ *(uint16_t*)0x20000094 = 5;
+ *(uint16_t*)0x20000096 = 1;
+ *(uint8_t*)0x20000098 = 7;
+ *(uint16_t*)0x2000009c = 9;
+ *(uint16_t*)0x2000009e = 2;
+ memcpy((void*)0x200000a0, "syz0\000", 5);
+ *(uint16_t*)0x200000a8 = 0x24;
+ STORE_BY_BITMASK(uint16_t, , 0x200000aa, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000ab, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000ab, 1, 7, 1);
+ *(uint16_t*)0x200000ac = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000ae, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000af, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000af, 0, 7, 1);
+ *(uint32_t*)0x200000b0 = htobe32(4);
+ *(uint16_t*)0x200000b4 = 9;
+ *(uint16_t*)0x200000b6 = 0x1a;
+ memcpy((void*)0x200000b8, "syz0\000", 5);
+ *(uint16_t*)0x200000c0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000c2, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000c3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000c3, 1, 7, 1);
+ *(uint16_t*)0x200000c4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000c6, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000c7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000c7, 0, 7, 1);
+ *(uint8_t*)0x200000c8 = 0xac;
+ *(uint8_t*)0x200000c9 = 0x14;
+ *(uint8_t*)0x200000ca = 0x14;
+ *(uint8_t*)0x200000cb = 0x16;
+ *(uint64_t*)0x20000148 = 0x4c;
+ *(uint64_t*)0x20000198 = 1;
+ *(uint64_t*)0x200001a0 = 0;
+ *(uint64_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001b0 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000180ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7108e32817eabfa942ef178898bfcc9665357b30.c b/syzkaller-repros/linux/7108e32817eabfa942ef178898bfcc9665357b30.c
new file mode 100644
index 0000000..e8f3c57
--- /dev/null
+++ b/syzkaller-repros/linux/7108e32817eabfa942ef178898bfcc9665357b30.c
@@ -0,0 +1,102 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x20000000;
+ *(uint64_t*)0x20000000 = 0x20000040;
+ *(uint32_t*)0x20000040 = 0x44;
+ *(uint8_t*)0x20000044 = 2;
+ *(uint8_t*)0x20000045 = 6;
+ *(uint16_t*)0x20000046 = 1;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint8_t*)0x20000050 = 0;
+ *(uint8_t*)0x20000051 = 0;
+ *(uint16_t*)0x20000052 = htobe16(0);
+ *(uint16_t*)0x20000054 = 0xc;
+ *(uint16_t*)0x20000056 = 3;
+ memcpy((void*)0x20000058, "hash:ip\000", 8);
+ *(uint16_t*)0x20000060 = 9;
+ *(uint16_t*)0x20000062 = 2;
+ memcpy((void*)0x20000064, "syz2\000", 5);
+ *(uint16_t*)0x2000006c = 5;
+ *(uint16_t*)0x2000006e = 1;
+ *(uint8_t*)0x20000070 = 7;
+ *(uint16_t*)0x20000074 = 5;
+ *(uint16_t*)0x20000076 = 4;
+ *(uint8_t*)0x20000078 = 0;
+ *(uint16_t*)0x2000007c = 5;
+ *(uint16_t*)0x2000007e = 5;
+ *(uint8_t*)0x20000080 = 0xa;
+ *(uint64_t*)0x20000008 = 0x44;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_sendmsg, r[1], 0ul, 0x41ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_sendmsg, r[2], 0ul, 0ul);
+ syscall(__NR_sendmsg, r[2], 0ul, 0x40804ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[3] = res;
+ *(uint64_t*)0x20000180 = 0x20000000;
+ *(uint16_t*)0x20000000 = 0x10;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 0xcf826992;
+ *(uint32_t*)0x20000188 = 0xc;
+ *(uint64_t*)0x20000190 = 0x20000140;
+ *(uint64_t*)0x20000140 = 0x20000040;
+ memcpy(
+ (void*)0x20000040,
+ "\xf4\x00\x00\x00\x0b\x06\x15\x0e\x2c\xbd\x70\x00\xfe\xdb\xdf\x25\x01\x00"
+ "\x00\x00\x09\x00\x02\x00\x73\x79\x7a\x32\x00\x00\x00\x00\x05\x00\x01\x00"
+ "\x07\x00\x00\x00\x08\x00\x09\x40\x00\x00\xd7\xb1\xa8\x00\x08\x80\x1c\x00"
+ "\x07\x80\x18\x00\x14\x80\x14\x00\x02\x40\xff\x02\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x01\x10\x00\x07\x80\x0c\x00\x18\x40\x00\x00"
+ "\x00\x00\x00\x00\x00\x07\x10\x00\x07\x80\x0a\x00\x11\x00\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\x00\x00\x10\x00\x07\x80\x09\x00\x13\x00\x73\x79\x7a\x30\x00\x00"
+ "\x00\x00\x10\x00\x07\x80\x0c\x00\x18\x40\x00\x00\x00\x00\x00\x00\x00\x03"
+ "\x18\x00\x07\x80\x14\x00\x17\x00\x73\x79\x7a\x6b\x61\x6c\x6c\x65\x72\x30"
+ "\x00\x00\x00\x00\x00\x00\x0c\x00\x07\x80\x06\x00\x04\x40\x4e\x21\x00\x00"
+ "\x0c\x00\x07\x80\x08\x00\x1c\x40\x00\x00\x7f\xff\x0c\x00\x07\x80\x06\x00"
+ "\x1d\x40\x01\x00\x00\x00\x0c\x00\x07\x80\x05\x00\xc6\x26\x04\x00\x00\x00"
+ "\x1c\x00\x07\x80\x08\x00\x09\x40\x00\x00\x00\x02\x06\x00\x1d\x40\xf4\x06"
+ "\x00\x00\x06\x00\x1d\x40\x00\x04\x00\x00",
+ 244);
+ *(uint64_t*)0x20000148 = 0xf4;
+ *(uint64_t*)0x20000198 = 1;
+ *(uint64_t*)0x200001a0 = 0;
+ *(uint64_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001b0 = 0x40000;
+ syscall(__NR_sendmsg, r[3], 0x20000180ul, 0x20000000ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7178f5e3c9146fc84a07bc87e3b40aa0b2fabe03.c b/syzkaller-repros/linux/7178f5e3c9146fc84a07bc87e3b40aa0b2fabe03.c
new file mode 100644
index 0000000..da2c7e9
--- /dev/null
+++ b/syzkaller-repros/linux/7178f5e3c9146fc84a07bc87e3b40aa0b2fabe03.c
@@ -0,0 +1,460 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+struct vusb_descriptor {
+ uint8_t req_type;
+ uint8_t desc_type;
+ uint32_t len;
+ char data[0];
+} __attribute__((packed));
+
+struct vusb_descriptors {
+ uint32_t len;
+ struct vusb_descriptor* generic;
+ struct vusb_descriptor* descs[0];
+} __attribute__((packed));
+
+struct vusb_response {
+ uint8_t type;
+ uint8_t req;
+ uint32_t len;
+ char data[0];
+} __attribute__((packed));
+
+struct vusb_responses {
+ uint32_t len;
+ struct vusb_response* generic;
+ struct vusb_response* resps[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_control_io(volatile long a0, volatile long a1,
+ volatile long a2)
+{
+ int fd = a0;
+ struct vusb_descriptors* descs = (struct vusb_descriptors*)a1;
+ struct vusb_responses* resps = (struct vusb_responses*)a2;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ int rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ return -1;
+ uint8_t req = event.ctrl.bRequest;
+ uint8_t req_type = event.ctrl.bRequestType & USB_TYPE_MASK;
+ uint8_t desc_type = event.ctrl.wValue >> 8;
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ if (req == USB_REQ_GET_DESCRIPTOR) {
+ int i;
+ int descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) /
+ sizeof(descs->descs[0]);
+ for (i = 0; i < descs_num; i++) {
+ struct vusb_descriptor* desc = descs->descs[i];
+ if (!desc)
+ continue;
+ if (desc->req_type == req_type && desc->desc_type == desc_type) {
+ response_length = desc->len;
+ if (response_length != 0)
+ response_data = &desc->data[0];
+ goto reply;
+ }
+ }
+ if (descs->generic) {
+ response_data = &descs->generic->data[0];
+ response_length = descs->generic->len;
+ goto reply;
+ }
+ } else {
+ int i;
+ int resps_num = (resps->len - offsetof(struct vusb_responses, resps)) /
+ sizeof(resps->resps[0]);
+ for (i = 0; i < resps_num; i++) {
+ struct vusb_response* resp = resps->resps[i];
+ if (!resp)
+ continue;
+ if (resp->type == req_type && resp->req == req) {
+ response_length = resp->len;
+ if (response_length != 0)
+ response_data = &resp->data[0];
+ goto reply;
+ }
+ }
+ if (resps->generic) {
+ response_data = &resps->generic->data[0];
+ response_length = resps->generic->len;
+ goto reply;
+ }
+ }
+ return -1;
+ struct usb_fuzzer_ep_io_data response;
+
+reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ sleep_ms(200);
+ return 0;
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ long res = 0;
+ *(uint8_t*)0x20000040 = 0x12;
+ *(uint8_t*)0x20000041 = 1;
+ *(uint16_t*)0x20000042 = 0;
+ *(uint8_t*)0x20000044 = 0x15;
+ *(uint8_t*)0x20000045 = 0xb4;
+ *(uint8_t*)0x20000046 = 0x45;
+ *(uint8_t*)0x20000047 = 8;
+ *(uint16_t*)0x20000048 = 0x4fa;
+ *(uint16_t*)0x2000004a = 0x2490;
+ *(uint16_t*)0x2000004c = 0xf52f;
+ *(uint8_t*)0x2000004e = 0;
+ *(uint8_t*)0x2000004f = 0;
+ *(uint8_t*)0x20000050 = 0;
+ *(uint8_t*)0x20000051 = 1;
+ *(uint8_t*)0x20000052 = 9;
+ *(uint8_t*)0x20000053 = 2;
+ *(uint16_t*)0x20000054 = 0x12;
+ *(uint8_t*)0x20000056 = 1;
+ *(uint8_t*)0x20000057 = 0;
+ *(uint8_t*)0x20000058 = 0;
+ *(uint8_t*)0x20000059 = 0;
+ *(uint8_t*)0x2000005a = 0;
+ *(uint8_t*)0x2000005b = 9;
+ *(uint8_t*)0x2000005c = 4;
+ *(uint8_t*)0x2000005d = 0x9d;
+ *(uint8_t*)0x2000005e = 0;
+ *(uint8_t*)0x2000005f = 0;
+ *(uint8_t*)0x20000060 = 0x80;
+ *(uint8_t*)0x20000061 = 0xe4;
+ *(uint8_t*)0x20000062 = 0x7a;
+ *(uint8_t*)0x20000063 = 0;
+ res = syz_usb_connect(6, 0x24, 0x20000040, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x200005c0 = 0x54;
+ *(uint64_t*)0x200005c4 = 0;
+ *(uint64_t*)0x200005cc = 0;
+ *(uint64_t*)0x200005d4 = 0;
+ *(uint64_t*)0x200005dc = 0x20000400;
+ *(uint8_t*)0x20000400 = 0;
+ *(uint8_t*)0x20000401 = 9;
+ *(uint32_t*)0x20000402 = 0;
+ *(uint64_t*)0x200005e4 = 0;
+ *(uint64_t*)0x200005ec = 0;
+ *(uint64_t*)0x200005f4 = 0;
+ *(uint64_t*)0x200005fc = 0;
+ *(uint64_t*)0x20000604 = 0;
+ *(uint64_t*)0x2000060c = 0;
+ syz_usb_control_io(r[0], 0, 0x200005c0);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/719d1c9a51751d6211725dd768a22aac812d5c16.c b/syzkaller-repros/linux/719d1c9a51751d6211725dd768a22aac812d5c16.c
new file mode 100644
index 0000000..dddb8b9
--- /dev/null
+++ b/syzkaller-repros/linux/719d1c9a51751d6211725dd768a22aac812d5c16.c
@@ -0,0 +1,66 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0xaul, 1ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000100 = 1;
+ syscall(__NR_setsockopt, r[0], 6ul, 0x13ul, 0x20000100ul, 4ul);
+ *(uint16_t*)0x20000300 = 0xa;
+ *(uint16_t*)0x20000302 = htobe16(0);
+ *(uint32_t*)0x20000304 = htobe32(0);
+ *(uint8_t*)0x20000308 = 0;
+ *(uint8_t*)0x20000309 = 0;
+ *(uint8_t*)0x2000030a = 0;
+ *(uint8_t*)0x2000030b = 0;
+ *(uint8_t*)0x2000030c = 0;
+ *(uint8_t*)0x2000030d = 0;
+ *(uint8_t*)0x2000030e = 0;
+ *(uint8_t*)0x2000030f = 0;
+ *(uint8_t*)0x20000310 = 0;
+ *(uint8_t*)0x20000311 = 0;
+ *(uint8_t*)0x20000312 = -1;
+ *(uint8_t*)0x20000313 = -1;
+ *(uint8_t*)0x20000314 = 0xac;
+ *(uint8_t*)0x20000315 = 0x14;
+ *(uint8_t*)0x20000316 = 0x14;
+ *(uint8_t*)0x20000317 = 0xaa;
+ *(uint32_t*)0x20000318 = 0;
+ syscall(__NR_connect, r[0], 0x20000300ul, 0x1cul);
+ memcpy((void*)0x20000340, "tls\000", 4);
+ syscall(__NR_setsockopt, r[0], 6ul, 0x1ful, 0x20000340ul, 4ul);
+ *(uint16_t*)0x20000180 = 0x303;
+ *(uint16_t*)0x20000182 = 0x34;
+ memcpy((void*)0x20000184, "\xe5\x73\xb0\x37\xde\x86\x16\xdc", 8);
+ memcpy((void*)0x2000018c,
+ "\xc4\x08\xee\x5d\xfa\x1b\xb5\xf0\x44\xb4\xea\x4a\xb5\x7a\x3a\x93\x29"
+ "\x43\x17\x02\x43\x33\x3b\x60\x85\x93\x35\x87\x82\x86\xb7\xfb",
+ 32);
+ memcpy((void*)0x200001ac, "\x99\x8a\x9d\xe9", 4);
+ memcpy((void*)0x200001b0, "\xff\xff\xff\xff\xff\xff\xff\xfe", 8);
+ syscall(__NR_setsockopt, r[0], 0x11aul, 1ul, 0x20000180ul, 0x38ul);
+ memcpy((void*)0x200001c0,
+ "\x36\x49\x12\x5c\xfe\xf1\x9c\x02\xad\xa8\x8a\x6e\x5b\x0f\x90\x85\xd7"
+ "\x7e\xfe",
+ 19);
+ syscall(__NR_sendto, r[0], 0x200001c0ul, 0xfffffdeful, 0ul, 0ul, 0ul);
+ *(uint32_t*)0x200001c0 = 2;
+ syscall(__NR_setsockopt, r[0], 0x29ul, 1ul, 0x200001c0ul, 4ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/72c38236aec3b42af48cc5b21c0dca0d536efcab.c b/syzkaller-repros/linux/72c38236aec3b42af48cc5b21c0dca0d536efcab.c
new file mode 100644
index 0000000..f44ae27
--- /dev/null
+++ b/syzkaller-repros/linux/72c38236aec3b42af48cc5b21c0dca0d536efcab.c
@@ -0,0 +1,254 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000440;
+ *(uint32_t*)0x20000440 = 0x50;
+ *(uint8_t*)0x20000444 = 2;
+ *(uint8_t*)0x20000445 = 6;
+ *(uint16_t*)0x20000446 = 1;
+ *(uint32_t*)0x20000448 = 0;
+ *(uint32_t*)0x2000044c = 0;
+ *(uint8_t*)0x20000450 = 0;
+ *(uint8_t*)0x20000451 = 0;
+ *(uint16_t*)0x20000452 = htobe16(0);
+ *(uint16_t*)0x20000454 = 9;
+ *(uint16_t*)0x20000456 = 2;
+ memcpy((void*)0x20000458, "syz2\000", 5);
+ *(uint16_t*)0x20000460 = 0xc;
+ *(uint16_t*)0x20000462 = 3;
+ memcpy((void*)0x20000464, "hash:ip\000", 8);
+ *(uint16_t*)0x2000046c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000046e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000046f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000046f, 1, 7, 1);
+ *(uint16_t*)0x20000470 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000472, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 0, 7, 1);
+ *(uint32_t*)0x20000474 = htobe32(3);
+ *(uint16_t*)0x20000478 = 5;
+ *(uint16_t*)0x2000047a = 1;
+ *(uint8_t*)0x2000047c = 7;
+ *(uint16_t*)0x20000480 = 5;
+ *(uint16_t*)0x20000482 = 4;
+ *(uint8_t*)0x20000484 = 0;
+ *(uint16_t*)0x20000488 = 5;
+ *(uint16_t*)0x2000048a = 5;
+ *(uint8_t*)0x2000048c = 2;
+ *(uint64_t*)0x200002c8 = 0x50;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0x200000000000000;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_sendmsg, r[1], 0ul, 0x1002c001ul);
+ syscall(__NR_socket, 0xaul, 3ul, 0x3aul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[2] = res;
+ *(uint64_t*)0x20000500 = 0;
+ *(uint32_t*)0x20000508 = 0;
+ *(uint64_t*)0x20000510 = 0x200004c0;
+ *(uint64_t*)0x200004c0 = 0x200003c0;
+ *(uint32_t*)0x200003c0 = 0x100;
+ *(uint8_t*)0x200003c4 = 0xb;
+ *(uint8_t*)0x200003c5 = 6;
+ *(uint16_t*)0x200003c6 = 1;
+ *(uint32_t*)0x200003c8 = 0x70bd2d;
+ *(uint32_t*)0x200003cc = 0x25dfdbfb;
+ *(uint8_t*)0x200003d0 = 0x9a;
+ *(uint8_t*)0x200003d1 = 0;
+ *(uint16_t*)0x200003d2 = htobe16(5);
+ *(uint16_t*)0x200003d4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200003d6, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200003d7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200003d7, 0, 7, 1);
+ *(uint32_t*)0x200003d8 = htobe32(0x40);
+ *(uint16_t*)0x200003dc = 0x44;
+ STORE_BY_BITMASK(uint16_t, , 0x200003de, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200003df, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200003df, 1, 7, 1);
+ *(uint16_t*)0x200003e0 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x200003e2, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200003e3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200003e3, 1, 7, 1);
+ *(uint16_t*)0x200003e4 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200003e6, 0x18, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200003e7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200003e7, 0, 7, 1);
+ *(uint64_t*)0x200003e8 = htobe64(3);
+ *(uint16_t*)0x200003f0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200003f2, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200003f3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200003f3, 1, 7, 1);
+ *(uint16_t*)0x200003f4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200003f6, 0xb, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200003f7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200003f7, 0, 7, 1);
+ *(uint32_t*)0x200003f8 = htobe32(0x81);
+ *(uint16_t*)0x200003fc = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200003fe, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200003ff, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200003ff, 1, 7, 1);
+ *(uint16_t*)0x20000400 = 5;
+ *(uint16_t*)0x20000402 = 0x1a;
+ memcpy((void*)0x20000404, "\000", 1);
+ *(uint16_t*)0x20000408 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000040a, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000040b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000040b, 1, 7, 1);
+ *(uint16_t*)0x2000040c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000040e, 0xa, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000040f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000040f, 0, 7, 1);
+ *(uint32_t*)0x20000410 = htobe32(8);
+ *(uint16_t*)0x20000414 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000416, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000417, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000417, 1, 7, 1);
+ *(uint16_t*)0x20000418 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x2000041a, 0x1d, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000041b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000041b, 0, 7, 1);
+ *(uint16_t*)0x2000041c = htobe16(0x3f);
+ *(uint16_t*)0x20000420 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000422, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000423, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000423, 0, 7, 1);
+ *(uint32_t*)0x20000424 = htobe32(9);
+ *(uint16_t*)0x20000428 = 5;
+ *(uint16_t*)0x2000042a = 1;
+ *(uint8_t*)0x2000042c = 7;
+ *(uint16_t*)0x20000430 = 5;
+ *(uint16_t*)0x20000432 = 1;
+ *(uint8_t*)0x20000434 = 7;
+ *(uint16_t*)0x20000438 = 5;
+ *(uint16_t*)0x2000043a = 1;
+ *(uint8_t*)0x2000043c = 7;
+ *(uint16_t*)0x20000440 = 9;
+ *(uint16_t*)0x20000442 = 2;
+ memcpy((void*)0x20000444, "syz2\000", 5);
+ *(uint16_t*)0x2000044c = 0x30;
+ STORE_BY_BITMASK(uint16_t, , 0x2000044e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000044f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000044f, 1, 7, 1);
+ *(uint16_t*)0x20000450 = 0x14;
+ *(uint16_t*)0x20000452 = 0x17;
+ memcpy((void*)0x20000454, "veth0_to_bridge\000", 16);
+ *(uint16_t*)0x20000464 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000466, 0xa, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000467, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000467, 0, 7, 1);
+ *(uint32_t*)0x20000468 = htobe32(0x2b);
+ *(uint16_t*)0x2000046c = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x2000046e, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000046f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000046f, 0, 7, 1);
+ *(uint16_t*)0x20000470 = htobe16(0x4e24);
+ *(uint16_t*)0x20000474 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000476, 0xb, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000477, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000477, 0, 7, 1);
+ *(uint32_t*)0x20000478 = htobe32(0x1f);
+ *(uint16_t*)0x2000047c = 0x44;
+ STORE_BY_BITMASK(uint16_t, , 0x2000047e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000047f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000047f, 1, 7, 1);
+ *(uint16_t*)0x20000480 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x20000482, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000483, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000483, 1, 7, 1);
+ *(uint16_t*)0x20000484 = 0x14;
+ STORE_BY_BITMASK(uint16_t, , 0x20000486, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000487, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000487, 0, 7, 1);
+ *(uint8_t*)0x20000488 = -1;
+ *(uint8_t*)0x20000489 = 2;
+ *(uint8_t*)0x2000048a = 0;
+ *(uint8_t*)0x2000048b = 0;
+ *(uint8_t*)0x2000048c = 0;
+ *(uint8_t*)0x2000048d = 0;
+ *(uint8_t*)0x2000048e = 0;
+ *(uint8_t*)0x2000048f = 0;
+ *(uint8_t*)0x20000490 = 0;
+ *(uint8_t*)0x20000491 = 0;
+ *(uint8_t*)0x20000492 = 0;
+ *(uint8_t*)0x20000493 = 0;
+ *(uint8_t*)0x20000494 = 0;
+ *(uint8_t*)0x20000495 = 0;
+ *(uint8_t*)0x20000496 = 0;
+ *(uint8_t*)0x20000497 = 1;
+ *(uint16_t*)0x20000498 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x2000049a, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000049b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000049b, 1, 7, 1);
+ *(uint16_t*)0x2000049c = 0x14;
+ STORE_BY_BITMASK(uint16_t, , 0x2000049e, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000049f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000049f, 0, 7, 1);
+ *(uint8_t*)0x200004a0 = 0xfe;
+ *(uint8_t*)0x200004a1 = 0x80;
+ *(uint8_t*)0x200004a2 = 0;
+ *(uint8_t*)0x200004a3 = 0;
+ *(uint8_t*)0x200004a4 = 0;
+ *(uint8_t*)0x200004a5 = 0;
+ *(uint8_t*)0x200004a6 = 0;
+ *(uint8_t*)0x200004a7 = 0;
+ *(uint8_t*)0x200004a8 = 0;
+ *(uint8_t*)0x200004a9 = 0;
+ *(uint8_t*)0x200004aa = 0;
+ *(uint8_t*)0x200004ab = 0;
+ *(uint8_t*)0x200004ac = 0;
+ *(uint8_t*)0x200004ad = 0;
+ *(uint8_t*)0x200004ae = 0;
+ *(uint8_t*)0x200004af = 0xa;
+ *(uint16_t*)0x200004b0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200004b2, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004b3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004b3, 0, 7, 1);
+ *(uint32_t*)0x200004b4 = htobe32(0x9b);
+ *(uint16_t*)0x200004b8 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200004ba, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004bb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004bb, 0, 7, 1);
+ *(uint32_t*)0x200004bc = htobe32(0x80);
+ *(uint64_t*)0x200004c8 = 0x100;
+ *(uint64_t*)0x20000518 = 1;
+ *(uint64_t*)0x20000520 = 0;
+ *(uint64_t*)0x20000528 = 0;
+ *(uint32_t*)0x20000530 = 0x40000;
+ syscall(__NR_sendmsg, r[2], 0x20000500ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/73442781849194e635547ef76611d132f9e3458f.c b/syzkaller-repros/linux/73442781849194e635547ef76611d132f9e3458f.c
new file mode 100644
index 0000000..647d579
--- /dev/null
+++ b/syzkaller-repros/linux/73442781849194e635547ef76611d132f9e3458f.c
@@ -0,0 +1,270 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_creat, 0ul, 0ul);
+ memcpy((void*)0x200003c0, "/sys/kernel/debug/bluetooth/6lowpan_enable\000",
+ 43);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200003c0ul, 2ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000140, "1", 1);
+ syscall(__NR_write, r[0], 0x20000140ul, 1ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 6; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/73635912ce586acdaa2cbe4206fa1414b095e6a1.c b/syzkaller-repros/linux/73635912ce586acdaa2cbe4206fa1414b095e6a1.c
new file mode 100644
index 0000000..ab302ef
--- /dev/null
+++ b/syzkaller-repros/linux/73635912ce586acdaa2cbe4206fa1414b095e6a1.c
@@ -0,0 +1,285 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ *(uint32_t*)0x204e7000 = 2;
+ *(uint32_t*)0x204e7004 = 0x70;
+ *(uint8_t*)0x204e7008 = 0xdf;
+ *(uint8_t*)0x204e7009 = 0;
+ *(uint8_t*)0x204e700a = 0;
+ *(uint8_t*)0x204e700b = 0;
+ *(uint32_t*)0x204e700c = 0;
+ *(uint64_t*)0x204e7010 = 0;
+ *(uint64_t*)0x204e7018 = 0;
+ *(uint64_t*)0x204e7020 = 0;
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 0, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 1, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 2, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 3, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 4, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 5, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 6, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 7, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 8, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 9, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 10, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 11, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 12, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 13, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 14, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 15, 2);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 17, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 18, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 19, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 20, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 21, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 22, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 23, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 24, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 25, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 26, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 2, 27, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 28, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x204e7028, 0, 29, 35);
+ *(uint32_t*)0x204e7030 = 0;
+ *(uint32_t*)0x204e7034 = 0;
+ *(uint64_t*)0x204e7038 = 0;
+ *(uint64_t*)0x204e7040 = 3;
+ *(uint64_t*)0x204e7048 = 0;
+ *(uint64_t*)0x204e7050 = 0;
+ *(uint32_t*)0x204e7058 = 0;
+ *(uint32_t*)0x204e705c = 0;
+ *(uint64_t*)0x204e7060 = 0;
+ *(uint32_t*)0x204e7068 = 0;
+ *(uint16_t*)0x204e706c = 0;
+ *(uint16_t*)0x204e706e = 0;
+ res = syscall(__NR_perf_event_open, 0x204e7000, 0, 0, -1, 0);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000400,
+ "cpu&00&_\n\000\001\b\000\001\234\323\0165\240\035=\004\n\034`"
+ "fo\215\314m\\v\375.\236\tbk1\336\352\033\r;\201\204\207-X\266,"
+ "\305\264\"7\"\265yt\202\373\035\203\370.- "
+ "\000\000\000(\351`D\001i\\\215l\206lh\250\374\200\336,Kt\364#\305]Y;"
+ "\3016v\371\211\t\006\276*\252&"
+ "\275\026xQ\216\363\326\032\375\320\004\'y\233|"
+ "\344\267\bE\355\227\200s\031W\267[\360%>MM\365\230\276^=q!"
+ "\246\017p\0012\000\273\276\235X5\257ep\020R\v&\257\250$"
+ "\1777V\355LJ4\317\a\001\325T\n\312\302\206_"
+ "\301\316\215\355bS\215\351t\202\3641zwr\346o\210\345\343\347Gcx\300"
+ "\221I\001\000\000\000\001\000\000\000K\236\345["
+ "\240\n\017\004\246\260sE)\212\320R\303\301,b "
+ "\034#IRz6\376J~\332\327_\376\037\345\206\261xu&"
+ "\373\362\277\350\177\221\223\253\005\0004\205\206l\215\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000",
+ 289);
+ syscall(__NR_ioctl, r[0], 0x40082406, 0x20000400);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7472331ea05c4d9bef2d34636f5941e800dee7cd.c b/syzkaller-repros/linux/7472331ea05c4d9bef2d34636f5941e800dee7cd.c
new file mode 100644
index 0000000..d9c8a64
--- /dev/null
+++ b/syzkaller-repros/linux/7472331ea05c4d9bef2d34636f5941e800dee7cd.c
@@ -0,0 +1,684 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+struct csum_inet {
+ uint32_t acc;
+};
+
+static void csum_inet_init(struct csum_inet* csum)
+{
+ csum->acc = 0;
+}
+
+static void csum_inet_update(struct csum_inet* csum, const uint8_t* data,
+ size_t length)
+{
+ if (length == 0)
+ return;
+ size_t i;
+ for (i = 0; i < length - 1; i += 2)
+ csum->acc += *(uint16_t*)&data[i];
+ if (length & 1)
+ csum->acc += (uint16_t)data[length - 1];
+ while (csum->acc > 0xffff)
+ csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16);
+}
+
+static uint16_t csum_inet_digest(struct csum_inet* csum)
+{
+ return ~csum->acc;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(int sock, const char* name, const void* addr,
+ int addrsize, const void* mac, int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ netlink_attr(NDA_DST, addr, addrsize);
+ netlink_attr(NDA_LLADDR, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+#define SYZ_TUN_MAX_PACKET_SIZE 1000
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in_addr, sizeof(in_addr), &macaddr,
+ ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in6_addr, sizeof(in6_addr), &macaddr,
+ ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN);
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+#define MAX_FRAGS 4
+struct vnet_fragmentation {
+ uint32_t full;
+ uint32_t count;
+ uint32_t frags[MAX_FRAGS];
+};
+
+static long syz_emit_ethernet(volatile long a0, volatile long a1,
+ volatile long a2)
+{
+ if (tunfd < 0)
+ return (uintptr_t)-1;
+ uint32_t length = a0;
+ char* data = (char*)a1;
+ struct vnet_fragmentation* frags = (struct vnet_fragmentation*)a2;
+ struct iovec vecs[MAX_FRAGS + 1];
+ uint32_t nfrags = 0;
+ if (!tun_frags_enabled || frags == NULL) {
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = length;
+ nfrags++;
+ } else {
+ bool full = true;
+ uint32_t i, count = 0;
+ full = frags->full;
+ count = frags->count;
+ if (count > MAX_FRAGS)
+ count = MAX_FRAGS;
+ for (i = 0; i < count && length != 0; i++) {
+ uint32_t size = 0;
+ size = frags->frags[i];
+ if (size > length)
+ size = length;
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = size;
+ nfrags++;
+ data += size;
+ length -= size;
+ }
+ if (length != 0 && (full || nfrags == 0)) {
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = length;
+ nfrags++;
+ }
+ }
+ return writev(tunfd, vecs, nfrags);
+}
+
+static void flush_tun()
+{
+ char data[SYZ_TUN_MAX_PACKET_SIZE];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+void execute_one(void)
+{
+ *(uint8_t*)0x20000080 = 0xaa;
+ *(uint8_t*)0x20000081 = 0xaa;
+ *(uint8_t*)0x20000082 = 0xaa;
+ *(uint8_t*)0x20000083 = 0xaa;
+ *(uint8_t*)0x20000084 = 0xaa;
+ *(uint8_t*)0x20000085 = 0xaa;
+ *(uint8_t*)0x20000086 = -1;
+ *(uint8_t*)0x20000087 = -1;
+ *(uint8_t*)0x20000088 = -1;
+ *(uint8_t*)0x20000089 = -1;
+ *(uint8_t*)0x2000008a = -1;
+ *(uint8_t*)0x2000008b = -1;
+ *(uint16_t*)0x2000008c = htobe16(0x86dd);
+ STORE_BY_BITMASK(uint8_t, , 0x2000008e, 0, 0, 4);
+ STORE_BY_BITMASK(uint8_t, , 0x2000008e, 6, 4, 4);
+ memcpy((void*)0x2000008f, "\xd8\x65\x2b", 3);
+ *(uint16_t*)0x20000092 = htobe16(0x14);
+ *(uint8_t*)0x20000094 = 0x2c;
+ *(uint8_t*)0x20000095 = 0;
+ *(uint8_t*)0x20000096 = 0xfe;
+ *(uint8_t*)0x20000097 = 0x80;
+ *(uint8_t*)0x20000098 = 0;
+ *(uint8_t*)0x20000099 = 0;
+ *(uint8_t*)0x2000009a = 0;
+ *(uint8_t*)0x2000009b = 0;
+ *(uint8_t*)0x2000009c = 0;
+ *(uint8_t*)0x2000009d = 0;
+ *(uint8_t*)0x2000009e = 0;
+ *(uint8_t*)0x2000009f = 0;
+ *(uint8_t*)0x200000a0 = 0;
+ *(uint8_t*)0x200000a1 = 0;
+ *(uint8_t*)0x200000a2 = 0;
+ *(uint8_t*)0x200000a3 = 0;
+ *(uint8_t*)0x200000a4 = 0;
+ *(uint8_t*)0x200000a5 = 0xaa;
+ *(uint8_t*)0x200000a6 = 0xfe;
+ *(uint8_t*)0x200000a7 = 0x80;
+ *(uint8_t*)0x200000a8 = 0;
+ *(uint8_t*)0x200000a9 = 0;
+ *(uint8_t*)0x200000aa = 0;
+ *(uint8_t*)0x200000ab = 0;
+ *(uint8_t*)0x200000ac = 0;
+ *(uint8_t*)0x200000ad = 0;
+ *(uint8_t*)0x200000ae = 0;
+ *(uint8_t*)0x200000af = 0;
+ *(uint8_t*)0x200000b0 = 0;
+ *(uint8_t*)0x200000b1 = 0;
+ *(uint8_t*)0x200000b2 = 0;
+ *(uint8_t*)0x200000b3 = 0;
+ *(uint8_t*)0x200000b4 = 0;
+ *(uint8_t*)0x200000b5 = 0xaa;
+ *(uint16_t*)0x200000b6 = htobe16(0);
+ *(uint16_t*)0x200000b8 = htobe16(0xfffe);
+ *(uint32_t*)0x200000ba = 0x41424344;
+ *(uint32_t*)0x200000be = 0x41424344;
+ STORE_BY_BITMASK(uint8_t, , 0x200000c2, 0, 0, 1);
+ STORE_BY_BITMASK(uint8_t, , 0x200000c2, 0, 1, 3);
+ STORE_BY_BITMASK(uint8_t, , 0x200000c2, 5, 4, 4);
+ *(uint8_t*)0x200000c3 = 0;
+ *(uint16_t*)0x200000c4 = htobe16(0);
+ *(uint16_t*)0x200000c6 = htobe16(0);
+ *(uint16_t*)0x200000c8 = htobe16(0);
+ struct csum_inet csum_1;
+ csum_inet_init(&csum_1);
+ csum_inet_update(&csum_1, (const uint8_t*)0x20000096, 16);
+ csum_inet_update(&csum_1, (const uint8_t*)0x200000a6, 16);
+ uint32_t csum_1_chunk_2 = 0x14000000;
+ csum_inet_update(&csum_1, (const uint8_t*)&csum_1_chunk_2, 4);
+ uint32_t csum_1_chunk_3 = 0x6000000;
+ csum_inet_update(&csum_1, (const uint8_t*)&csum_1_chunk_3, 4);
+ csum_inet_update(&csum_1, (const uint8_t*)0x200000b6, 20);
+ *(uint16_t*)0x200000c6 = csum_inet_digest(&csum_1);
+ syz_emit_ethernet(0x4a, 0x20000080, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_binfmt_misc();
+ setup_leak();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7549a7ef3c7db3bf65acad1f27c5dba18f8d9bee.c b/syzkaller-repros/linux/7549a7ef3c7db3bf65acad1f27c5dba18f8d9bee.c
new file mode 100644
index 0000000..69a9729
--- /dev/null
+++ b/syzkaller-repros/linux/7549a7ef3c7db3bf65acad1f27c5dba18f8d9bee.c
@@ -0,0 +1,168 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x200002c0, "/dev/fd#\000", 9);
+ res = syz_open_dev(0x200002c0, 0x691, 2);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x241ul, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/78456bb7e9b0e4c786f3b5452e83978e2d249804.c b/syzkaller-repros/linux/78456bb7e9b0e4c786f3b5452e83978e2d249804.c
new file mode 100644
index 0000000..bd3a7c6
--- /dev/null
+++ b/syzkaller-repros/linux/78456bb7e9b0e4c786f3b5452e83978e2d249804.c
@@ -0,0 +1,454 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+void execute_one(void)
+{
+ *(uint8_t*)0x20000040 = 0x12;
+ *(uint8_t*)0x20000041 = 1;
+ *(uint16_t*)0x20000042 = 0;
+ *(uint8_t*)0x20000044 = 0x36;
+ *(uint8_t*)0x20000045 = 0x3d;
+ *(uint8_t*)0x20000046 = 0x83;
+ *(uint8_t*)0x20000047 = 0x40;
+ *(uint16_t*)0x20000048 = 0x11ba;
+ *(uint16_t*)0x2000004a = 0x1001;
+ *(uint16_t*)0x2000004c = 0xc29f;
+ *(uint8_t*)0x2000004e = 0;
+ *(uint8_t*)0x2000004f = 0;
+ *(uint8_t*)0x20000050 = 0;
+ *(uint8_t*)0x20000051 = 1;
+ *(uint8_t*)0x20000052 = 9;
+ *(uint8_t*)0x20000053 = 2;
+ *(uint16_t*)0x20000054 = 0x12;
+ *(uint8_t*)0x20000056 = 1;
+ *(uint8_t*)0x20000057 = 0;
+ *(uint8_t*)0x20000058 = 0;
+ *(uint8_t*)0x20000059 = 0;
+ *(uint8_t*)0x2000005a = 0;
+ *(uint8_t*)0x2000005b = 9;
+ *(uint8_t*)0x2000005c = 4;
+ *(uint8_t*)0x2000005d = 0xe5;
+ *(uint8_t*)0x2000005e = 0;
+ *(uint8_t*)0x2000005f = 0;
+ *(uint8_t*)0x20000060 = 7;
+ *(uint8_t*)0x20000061 = 0xa3;
+ *(uint8_t*)0x20000062 = 0x13;
+ *(uint8_t*)0x20000063 = 2;
+ syz_usb_connect(4, 0x24, 0x20000040, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7a326b12c63a0cb0927b54486cc88e12e7d296d5.c b/syzkaller-repros/linux/7a326b12c63a0cb0927b54486cc88e12e7d296d5.c
new file mode 100644
index 0000000..b81a048
--- /dev/null
+++ b/syzkaller-repros/linux/7a326b12c63a0cb0927b54486cc88e12e7d296d5.c
@@ -0,0 +1,230 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x1e, 2, 0);
+ if (res != -1)
+ r[0] = res;
+ res = syscall(__NR_socket, 0x1e, 2, 0);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x20000000 = 0x1e;
+ *(uint8_t*)0x20000002 = 1;
+ *(uint8_t*)0x20000003 = 0;
+ *(uint32_t*)0x20000004 = 0x41;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ syscall(__NR_bind, r[1], 0x20000000, 0x10);
+ *(uint32_t*)0x20000080 = 0x41;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ syscall(__NR_setsockopt, r[1], 0x10f, 0x87, 0x20000080, 0x10);
+ *(uint32_t*)0x200000c0 = 0x41;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = 2;
+ *(uint32_t*)0x200000cc = 0;
+ syscall(__NR_setsockopt, r[0], 0x10f, 0x87, 0x200000c0, 0x10);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7b1d73f9b987611883418c85c23926a2a3ed3853.c b/syzkaller-repros/linux/7b1d73f9b987611883418c85c23926a2a3ed3853.c
new file mode 100644
index 0000000..d2b000d
--- /dev/null
+++ b/syzkaller-repros/linux/7b1d73f9b987611883418c85c23926a2a3ed3853.c
@@ -0,0 +1,533 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ check_leaks();
+ }
+}
+
+void execute_one(void)
+{
+ memcpy((void*)0x20000000, "./file0\000", 8);
+ syscall(__NR_mkdirat, 0xffffff9c, 0x20000000, 0);
+ syscall(__NR_openat, 0xffffffffffffff9c, 0, 2, 0);
+ memcpy((void*)0x20000080, "./file0\000", 8);
+ memcpy((void*)0x200001c0, "fuse\000", 5);
+ inject_fault(38);
+ syscall(__NR_mount, 0, 0x20000080, 0x200001c0, 0, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ setup_fault();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7caa19bc225b467b96fe870bb2f33d2278ee2eed.c b/syzkaller-repros/linux/7caa19bc225b467b96fe870bb2f33d2278ee2eed.c
new file mode 100644
index 0000000..537e084
--- /dev/null
+++ b/syzkaller-repros/linux/7caa19bc225b467b96fe870bb2f33d2278ee2eed.c
@@ -0,0 +1,210 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ *(uint32_t*)0x20000140 = 0xa;
+ *(uint32_t*)0x20000144 = 3;
+ *(uint32_t*)0x20000148 = 0x6c0d;
+ *(uint32_t*)0x2000014c = 1;
+ *(uint32_t*)0x20000150 = 2;
+ *(uint32_t*)0x20000154 = -1;
+ *(uint32_t*)0x20000158 = 0;
+ *(uint8_t*)0x2000015c = 0;
+ *(uint8_t*)0x2000015d = 0;
+ *(uint8_t*)0x2000015e = 0;
+ *(uint8_t*)0x2000015f = 0;
+ *(uint8_t*)0x20000160 = 0;
+ *(uint8_t*)0x20000161 = 0;
+ *(uint8_t*)0x20000162 = 0;
+ *(uint8_t*)0x20000163 = 0;
+ *(uint8_t*)0x20000164 = 0;
+ *(uint8_t*)0x20000165 = 0;
+ *(uint8_t*)0x20000166 = 0;
+ *(uint8_t*)0x20000167 = 0;
+ *(uint8_t*)0x20000168 = 0;
+ *(uint8_t*)0x20000169 = 0;
+ *(uint8_t*)0x2000016a = 0;
+ *(uint8_t*)0x2000016b = 0;
+ *(uint32_t*)0x2000016c = 0;
+ *(uint32_t*)0x20000170 = -1;
+ *(uint32_t*)0x20000174 = 0;
+ *(uint32_t*)0x20000178 = 0;
+ *(uint32_t*)0x2000017c = 0;
+ res = syscall(__NR_bpf, 0ul, 0x20000140ul, 0x3cul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000180 = r[0];
+ *(uint64_t*)0x20000188 = 0x20000000;
+ *(uint64_t*)0x20000190 = 0x20000080;
+ *(uint64_t*)0x20000198 = 0;
+ syscall(__NR_bpf, 2ul, 0x20000180ul, 0x20ul);
+ *(uint32_t*)0x20000340 = r[0];
+ *(uint64_t*)0x20000348 = 0x20000300;
+ *(uint64_t*)0x20000350 = 0x20000340;
+ *(uint64_t*)0x20000358 = 0;
+ syscall(__NR_bpf, 2ul, 0x20000340ul, 0x20ul);
+ *(uint64_t*)0x20000100 = 0;
+ *(uint64_t*)0x20000108 = 0;
+ *(uint64_t*)0x20000110 = 0;
+ *(uint64_t*)0x20000118 = 0;
+ *(uint32_t*)0x20000120 = 0x101;
+ *(uint32_t*)0x20000124 = r[0];
+ *(uint64_t*)0x20000128 = 0;
+ *(uint64_t*)0x20000130 = 0;
+ syscall(__NR_bpf, 0x19ul, 0x20000100ul, 0x38ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7cbb8a66a79c83d5e96c8aad6b16d5791f738c74.c b/syzkaller-repros/linux/7cbb8a66a79c83d5e96c8aad6b16d5791f738c74.c
new file mode 100644
index 0000000..7681d95
--- /dev/null
+++ b/syzkaller-repros/linux/7cbb8a66a79c83d5e96c8aad6b16d5791f738c74.c
@@ -0,0 +1,607 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syz_open_dev(0, 0, 0x400);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ NONFAILING(memcpy((void*)0x20000240, "/dev/nbd#\000", 10));
+ res = syz_open_dev(0x20000240, 0, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ res = syscall(__NR_socketpair, 0x1eul, 0x80005ul, 0, 0x20000040ul);
+ if (res != -1)
+ NONFAILING(r[2] = *(uint32_t*)0x20000044);
+ break;
+ case 3:
+ syscall(__NR_ioctl, r[1], 0xab00ul, r[2]);
+ break;
+ case 4:
+ syscall(__NR_ioctl, r[0], 0xab03ul, 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7cc74fe65940458cb736edab0104aa2cf53faea1.c b/syzkaller-repros/linux/7cc74fe65940458cb736edab0104aa2cf53faea1.c
new file mode 100644
index 0000000..047fff0
--- /dev/null
+++ b/syzkaller-repros/linux/7cc74fe65940458cb736edab0104aa2cf53faea1.c
@@ -0,0 +1,230 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0xa, 0x40122000000003, 0x11);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x200001c0 = -1;
+ syscall(__NR_setsockopt, r[0], 0x29, 0x24, 0x200001c0, 4);
+ *(uint64_t*)0x20003840 = 0x20000040;
+ *(uint16_t*)0x20000040 = 0;
+ *(uint8_t*)0x20000042 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20003848 = 0x80;
+ *(uint64_t*)0x20003850 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000100;
+ memcpy((void*)0x20000100,
+ "\xf4\x00\x11\x00\x00\x2b\x2c\x25\xe9\x94\xef\xd1\x00\x00\x00\x00\x00"
+ "\x09\x11\x00\x00\x00\x00\x00\x00\x3a\x00\x00\x00\x00\xf6\x8a\xb9\x28"
+ "\xab\xff\xb7\xa8\xd4\xf3\x2e\xbd\xbe\xd8\x28\x84\x7b\xba\xeb\x4e",
+ 50);
+ *(uint64_t*)0x200000c8 = 0x32;
+ *(uint64_t*)0x20003858 = 1;
+ *(uint64_t*)0x20003860 = 0;
+ *(uint64_t*)0x20003868 = 0;
+ *(uint32_t*)0x20003870 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20003840, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/7fd99cec32407752014226ed25778bd75b6d322f.c b/syzkaller-repros/linux/7fd99cec32407752014226ed25778bd75b6d322f.c
new file mode 100644
index 0000000..fdde3f7
--- /dev/null
+++ b/syzkaller-repros/linux/7fd99cec32407752014226ed25778bd75b6d322f.c
@@ -0,0 +1,348 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+__attribute__((noreturn)) static void doexit(int status)
+{
+ volatile unsigned i;
+ syscall(__NR_exit_group, status);
+ for (i = 0;; i++) {
+ }
+}
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+const int kFailStatus = 67;
+const int kRetryStatus = 69;
+
+static void fail(const char* msg, ...)
+{
+ int e = errno;
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, " (errno %d)\n", e);
+ doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
+}
+
+static uint64_t current_time_ms()
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ fail("clock_gettime failed");
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static uintptr_t syz_open_procfs(uintptr_t a0, uintptr_t a1)
+{
+
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ if (a0 == 0) {
+ snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1);
+ } else if (a0 == (uintptr_t)-1) {
+ snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1);
+ } else {
+ snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0, (char*)a1);
+ }
+ int fd = open(buf, O_RDWR);
+ if (fd == -1)
+ fd = open(buf, O_RDONLY);
+ return fd;
+}
+
+static void execute_one();
+extern unsigned long long procid;
+
+static void loop()
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ fail("clone failed");
+ if (pid == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ execute_one();
+ doexit(0);
+ }
+
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ int res = waitpid(-1, &status, __WALL | WNOHANG);
+ if (res == pid) {
+ break;
+ }
+ usleep(1000);
+ if (current_time_ms() - start < 3 * 1000)
+ continue;
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ break;
+ }
+ }
+}
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (__atomic_load_n(&running, __ATOMIC_RELAXED))
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[5] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0x0, 0x0};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000480, "./file0", 8);
+ syscall(__NR_mkdir, 0x20000480, 0);
+ break;
+ case 1:
+ memcpy((void*)0x20000180, "mountinfo", 10);
+ res = syz_open_procfs(0, 0x20000180);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ memcpy((void*)0x2000a000, "./file0", 8);
+ memcpy((void*)0x20026ff8, "./file0", 8);
+ memcpy((void*)0x200001c0, "ramfs", 6);
+ syscall(__NR_mount, 0x2000a000, 0x20026ff8, 0x200001c0, 0, 0x20000380);
+ break;
+ case 3:
+ memcpy((void*)0x20d04000, "./file0", 8);
+ memcpy((void*)0x20903000, "./file0", 8);
+ memcpy((void*)0x20000340, "bdev", 5);
+ syscall(__NR_mount, 0x20d04000, 0x20903000, 0x20000340, 0x100000,
+ 0x200002c0);
+ break;
+ case 4:
+ memcpy((void*)0x20000240, "./file0", 8);
+ memcpy((void*)0x20000280, ".", 1);
+ memcpy((void*)0x20000040, "\x04\x5b\x89\x8f\x73", 5);
+ syscall(__NR_mount, 0x20000240, 0x20000280, 0x20000040, 0x1004, 0);
+ break;
+ case 5:
+ syscall(__NR_socketpair, 1, 2, 0, 0x207a0000);
+ break;
+ case 6:
+ res = syscall(__NR_socketpair, 1, 5, 0, 0x20616ff8);
+ if (res != -1) {
+ r[1] = *(uint32_t*)0x20616ff8;
+ r[2] = *(uint32_t*)0x20616ffc;
+ }
+ break;
+ case 7:
+ *(uint64_t*)0x20bba000 = 0x203a2000;
+ *(uint16_t*)0x203a2000 = 0;
+ *(uint8_t*)0x203a2002 = 0;
+ *(uint32_t*)0x203a2004 = 0;
+ *(uint32_t*)0x20bba008 = 0x6e;
+ *(uint64_t*)0x20bba010 = 0x206c6ff0;
+ *(uint64_t*)0x20bba018 = 0;
+ *(uint64_t*)0x20bba020 = 0x209dffb8;
+ *(uint64_t*)0x20bba028 = 0;
+ *(uint32_t*)0x20bba030 = 0;
+ syscall(__NR_sendmsg, r[2], 0x20bba000, 0);
+ break;
+ case 8:
+ memcpy((void*)0x20000080, "id_resolver", 12);
+ *(uint8_t*)0x200000c0 = 0x73;
+ *(uint8_t*)0x200000c1 = 0x79;
+ *(uint8_t*)0x200000c2 = 0x7a;
+ *(uint8_t*)0x200000c3 = 0x23;
+ *(uint8_t*)0x200000c4 = 0;
+ memcpy((void*)0x20000100, "nodev", 6);
+ res = syscall(__NR_request_key, 0x20000080, 0x200000c0, 0x20000100, 0);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 9:
+ memcpy((void*)0x20000140, "user", 5);
+ *(uint8_t*)0x20000180 = 0x73;
+ *(uint8_t*)0x20000181 = 0x79;
+ *(uint8_t*)0x20000182 = 0x7a;
+ *(uint8_t*)0x20000183 = 0x22;
+ *(uint8_t*)0x20000184 = 0;
+ syscall(__NR_add_key, 0x20000140, 0x20000180, 0x200001c0, 0, 0xfffffff8);
+ break;
+ case 10:
+ memcpy((void*)0x20000200, "big_key", 8);
+ *(uint8_t*)0x20000240 = 0x73;
+ *(uint8_t*)0x20000241 = 0x79;
+ *(uint8_t*)0x20000242 = 0x7a;
+ *(uint8_t*)0x20000243 = 0x22;
+ *(uint8_t*)0x20000244 = 0;
+ memcpy((void*)0x20000280, "", 1);
+ res = syscall(__NR_request_key, 0x20000200, 0x20000240, 0x20000280,
+ 0xfffffffe);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 11:
+ *(uint32_t*)0x200002c0 = r[3];
+ *(uint32_t*)0x200002c4 = 0;
+ *(uint32_t*)0x200002c8 = r[4];
+ syscall(__NR_keyctl, 0x17, 0x200002c0, 0x20000400, 0xdd, 0);
+ break;
+ case 12:
+ *(uint64_t*)0x200003c0 = 0x20000000;
+ *(uint16_t*)0x20000000 = 0;
+ *(uint8_t*)0x20000002 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x200003c8 = 0x6e;
+ *(uint64_t*)0x200003d0 = 0x20000340;
+ *(uint64_t*)0x200003d8 = 0;
+ *(uint64_t*)0x200003e0 = 0x20000380;
+ *(uint64_t*)0x20000380 = 0x18;
+ *(uint32_t*)0x20000388 = 1;
+ *(uint32_t*)0x2000038c = 1;
+ *(uint32_t*)0x20000390 = r[1];
+ *(uint64_t*)0x200003e8 = 0x18;
+ *(uint32_t*)0x200003f0 = 0;
+ syscall(__NR_sendmsg, r[2], 0x200003c0, 0);
+ break;
+ case 13:
+ *(uint64_t*)0x20e4ffc8 = 0x20beb000;
+ *(uint16_t*)0x20beb000 = 0;
+ *(uint8_t*)0x20beb002 = 0;
+ *(uint32_t*)0x20beb004 = 0;
+ *(uint32_t*)0x20e4ffd0 = 8;
+ *(uint64_t*)0x20e4ffd8 = 0x2000d000;
+ *(uint64_t*)0x20e4ffe0 = 0;
+ *(uint64_t*)0x20e4ffe8 = 0x2053c000;
+ *(uint64_t*)0x2053c000 = 0x18;
+ *(uint32_t*)0x2053c008 = 1;
+ *(uint32_t*)0x2053c00c = 1;
+ *(uint32_t*)0x2053c010 = r[1];
+ *(uint64_t*)0x20e4fff0 = 0x18;
+ *(uint32_t*)0x20e4fff8 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20e4ffc8, 0);
+ break;
+ case 14:
+ syscall(__NR_eventfd, 6);
+ break;
+ case 15:
+ syscall(__NR_close, r[1]);
+ break;
+ case 16:
+ memcpy((void*)0x200008c0, ".", 1);
+ memcpy((void*)0x200000c0, "./file0", 8);
+ memcpy((void*)0x20000000, "mslos", 6);
+ syscall(__NR_mount, 0x200008c0, 0x200000c0, 0x20000000, 0x200000000005010,
+ 0x20000200);
+ break;
+ case 17:
+ memcpy((void*)0x20000080, "./file1", 8);
+ memcpy((void*)0x20000100, "./file0", 8);
+ memcpy((void*)0x20000140, "ext4", 5);
+ syscall(__NR_mount, 0x20000080, 0x20000100, 0x20000140, 0x102000c,
+ 0x200003c0);
+ break;
+ case 18:
+ memcpy((void*)0x20377ff8, ".", 1);
+ memcpy((void*)0x20187ff8, ".", 1);
+ memcpy((void*)0x20753000, "mslos", 6);
+ syscall(__NR_mount, 0x20377ff8, 0x20187ff8, 0x20753000, 0x5010, 0x200e7000);
+ break;
+ case 19:
+ *(uint64_t*)0x200023c0 = 0x200012c0;
+ *(uint64_t*)0x200023c8 = 0x1000;
+ syscall(__NR_preadv, r[0], 0x200023c0, 0x1000000000000205, 0);
+ break;
+ }
+}
+
+void execute_one()
+{
+ execute(20);
+ collide = 1;
+ execute(20);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (;;) {
+ loop();
+ }
+}
diff --git a/syzkaller-repros/linux/804f59cfabd90cf56da1d83c9fdc19267fbfc0f8.c b/syzkaller-repros/linux/804f59cfabd90cf56da1d83c9fdc19267fbfc0f8.c
new file mode 100644
index 0000000..f2f7b56
--- /dev/null
+++ b/syzkaller-repros/linux/804f59cfabd90cf56da1d83c9fdc19267fbfc0f8.c
@@ -0,0 +1,256 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000240, "/dev/i2c-#\000", 11);
+ res = syz_open_dev(0x20000240, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x200001c0 = 0x20000000;
+ *(uint16_t*)0x20000000 = 9;
+ *(uint16_t*)0x20000002 = 0x600;
+ *(uint16_t*)0x20000004 = 0xbf;
+ *(uint64_t*)0x20000008 = 0x20000080;
+ memcpy(
+ (void*)0x20000080,
+ "\x38\xa1\x58\x01\xcc\xc0\x2d\x93\x07\xf5\x85\xe8\xc1\x92\x36\x9c\xd2\x8a"
+ "\x20\x65\xa7\x2b\xef\xe7\x6d\x26\xb6\x89\x0b\x75\x87\xfe\x41\x2a\xcd\x9c"
+ "\x9b\xcb\x71\x7a\x0f\xa9\x39\x71\xf6\x37\xe8\x38\xd8\xfe\xf9\x92\x4e\xbd"
+ "\xab\x08\x96\x6a\x85\x4a\xee\x45\x58\xa6\x2f\x26\xb9\x85\x86\xf9\xe2\xa7"
+ "\x60\xed\x50\xb5\xc2\x0f\x5a\x71\xdb\x91\x2e\x31\xeb\x0c\x5c\x1a\x15\xc3"
+ "\x6c\x4d\x3d\x06\x4d\x0f\xa7\xc9\x31\x44\x0c\x07\x81\xa7\x85\x90\x33\x1e"
+ "\x17\x9f\xff\x5d\x4e\x95\xfa\x9f\xa9\x71\x44\xbb\xb3\xb9\x10\x64\xd0\x12"
+ "\xf7\x9f\x8a\xe5\xe4\x71\xdd\x05\xd1\x68\xef\xbd\xaa\x98\xd3\xea\x92\x77"
+ "\x4e\x2c\x21\x60\xf6\x30\xd1\x1b\xab\xbf\xdc\x40\x63\xc2\x90\x4c\x54\x1c"
+ "\x86\x19\xb1\x9a\xe9\xc8\x31\x30\x24\xd8\xbe\xb9\x84\xcf\x29\x6f\x32\x5c"
+ "\x2e\x40\x5e\xe1\x7c\xf6\x0c\x2f\x21\x71\x49",
+ 191);
+ *(uint16_t*)0x20000010 = 0;
+ *(uint16_t*)0x20000012 = 0x1601;
+ *(uint16_t*)0x20000014 = 0;
+ *(uint64_t*)0x20000018 = 0;
+ *(uint32_t*)0x200001c8 = 2;
+ syscall(__NR_ioctl, r[0], 0x707, 0x200001c0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/82cfa36c1b9421e6e4148cca731f7ef35c0080a8.c b/syzkaller-repros/linux/82cfa36c1b9421e6e4148cca731f7ef35c0080a8.c
new file mode 100644
index 0000000..8a82974
--- /dev/null
+++ b/syzkaller-repros/linux/82cfa36c1b9421e6e4148cca731f7ef35c0080a8.c
@@ -0,0 +1,59 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000080, "/dev/dri/card#\000", 15);
+ res = syz_open_dev(0x20000080, 1, 0x121000);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ syscall(__NR_ioctl, r[0], 0xc02c563a, 0x20000040);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/84565948d3b91a924f2a3723e1c60b40248ab2f4.c b/syzkaller-repros/linux/84565948d3b91a924f2a3723e1c60b40248ab2f4.c
new file mode 100644
index 0000000..a966ce5
--- /dev/null
+++ b/syzkaller-repros/linux/84565948d3b91a924f2a3723e1c60b40248ab2f4.c
@@ -0,0 +1,447 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x200000c0 = 3;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 5;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint64_t*)0x200000d8 = 0;
+ syscall(__NR_ioctl, r[0], 0x4b72ul, 0x200000c0ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ *(uint32_t*)0x20000200 = 0x81;
+ *(uint32_t*)0x20000204 = 0;
+ *(uint32_t*)0x20000208 = 0;
+ *(uint32_t*)0x2000020c = 0;
+ *(uint8_t*)0x20000210 = 0;
+ memcpy((void*)0x20000211,
+ "\x49\xd9\xfe\x4d\xa0\x87\xf5\xd6\xf1\x0f\x99\x76\x12\x7b\xcf\x86\xfe"
+ "\x01\xfe",
+ 19);
+ syscall(__NR_ioctl, r[1], 0x4b60ul, 0x20000200ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[2] = res;
+ *(uint32_t*)0x20000200 = 0x81;
+ *(uint32_t*)0x20000204 = 0;
+ *(uint32_t*)0x20000208 = 0;
+ *(uint32_t*)0x2000020c = 0;
+ *(uint8_t*)0x20000210 = 0;
+ memcpy((void*)0x20000211,
+ "\x49\xd9\xfe\x4d\xa0\x87\xf5\xd6\xf1\x0f\x99\x76\x12\x7b\xcf\x86\xfe"
+ "\x01\xfe",
+ 19);
+ syscall(__NR_ioctl, r[2], 0x4b61ul, 0x20000200ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/84f365fefa97fd8af5d1de35909ae9ac93bb5c79.c b/syzkaller-repros/linux/84f365fefa97fd8af5d1de35909ae9ac93bb5c79.c
new file mode 100644
index 0000000..1c05f74
--- /dev/null
+++ b/syzkaller-repros/linux/84f365fefa97fd8af5d1de35909ae9ac93bb5c79.c
@@ -0,0 +1,1114 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(int sock, const char* name, const void* addr,
+ int addrsize, const void* mac, int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ netlink_attr(NDA_DST, addr, addrsize);
+ netlink_attr(NDA_LLADDR, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+#define SYZ_TUN_MAX_PACKET_SIZE 1000
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in_addr, sizeof(in_addr), &macaddr,
+ ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in6_addr, sizeof(in6_addr), &macaddr,
+ ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[SYZ_TUN_MAX_PACKET_SIZE];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 8; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ check_leaks();
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0xa, 1, 0x84);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ res = syscall(__NR_perf_event_open, 0, 0, -1, -1, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ syscall(__NR_sendmsg, r[1], 0, 0x40);
+ break;
+ case 3:
+ *(uint16_t*)0x20ef8cfd = 0xa;
+ *(uint16_t*)0x20ef8cff = htobe16(0x4e23);
+ *(uint32_t*)0x20ef8d01 = htobe32(0);
+ *(uint64_t*)0x20ef8d05 = htobe64(0);
+ *(uint64_t*)0x20ef8d0d = htobe64(1);
+ *(uint32_t*)0x20ef8d15 = 0;
+ syscall(__NR_bind, r[0], 0x20ef8cfd, 0x1c);
+ break;
+ case 4:
+ syscall(__NR_listen, r[0], 1);
+ break;
+ case 5:
+ res = syscall(__NR_socket, 0xa, 5, 0x84);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 6:
+ inject_fault(11);
+ syscall(__NR_accept4, r[0], 0, 0, 0);
+ break;
+ case 7:
+ *(uint16_t*)0x2055bfe4 = 0xa;
+ *(uint16_t*)0x2055bfe6 = htobe16(0x4e23);
+ *(uint32_t*)0x2055bfe8 = htobe32(0);
+ *(uint64_t*)0x2055bfec = htobe64(0);
+ *(uint64_t*)0x2055bff4 = htobe64(1);
+ *(uint32_t*)0x2055bffc = 0;
+ syscall(__NR_setsockopt, r[2], 0x84, 0x6b, 0x2055bfe4, 0x1c);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ setup_fault();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/8526f2731ca76af1808f6408d11a5accd819572a.c b/syzkaller-repros/linux/8526f2731ca76af1808f6408d11a5accd819572a.c
new file mode 100644
index 0000000..852e0ac
--- /dev/null
+++ b/syzkaller-repros/linux/8526f2731ca76af1808f6408d11a5accd819572a.c
@@ -0,0 +1,617 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 7; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_socket, 2ul, 1ul, 0ul);
+ break;
+ case 1:
+ res = syscall(__NR_pipe, 0x20000700ul);
+ if (res != -1) {
+ r[0] = *(uint32_t*)0x20000700;
+ r[1] = *(uint32_t*)0x20000704;
+ }
+ break;
+ case 2:
+ syscall(__NR_write, r[1], 0x20000340ul, 0x41395527ul);
+ break;
+ case 3:
+ *(uint32_t*)0x2001d000 = 1;
+ *(uint32_t*)0x2001d004 = 0x70;
+ *(uint8_t*)0x2001d008 = 0;
+ *(uint8_t*)0x2001d009 = 0;
+ *(uint8_t*)0x2001d00a = 0;
+ *(uint8_t*)0x2001d00b = 0;
+ *(uint32_t*)0x2001d00c = 0;
+ *(uint64_t*)0x2001d010 = 0x7f;
+ *(uint64_t*)0x2001d018 = 0;
+ *(uint64_t*)0x2001d020 = 0;
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 0, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 1, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 2, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 3, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 4, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 3, 5, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 6, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 7, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 8, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 9, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 10, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 11, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 12, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 13, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 14, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 15, 2);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 17, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 18, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 19, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 20, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 21, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 22, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 23, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 24, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 25, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 26, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 27, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 28, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 29, 35);
+ *(uint32_t*)0x2001d030 = 0;
+ *(uint32_t*)0x2001d034 = 0;
+ *(uint64_t*)0x2001d038 = 0;
+ *(uint64_t*)0x2001d040 = 0;
+ *(uint64_t*)0x2001d048 = 0;
+ *(uint64_t*)0x2001d050 = 0;
+ *(uint32_t*)0x2001d058 = 0;
+ *(uint32_t*)0x2001d05c = 0;
+ *(uint64_t*)0x2001d060 = 0;
+ *(uint32_t*)0x2001d068 = 0;
+ *(uint16_t*)0x2001d06c = 0;
+ *(uint16_t*)0x2001d06e = 0;
+ syscall(__NR_perf_event_open, 0x2001d000ul, 0, 0ul, -1, 0ul);
+ break;
+ case 4:
+ syscall(__NR_socketpair, 1ul, 1ul, 0ul, 0x20000040ul);
+ break;
+ case 5:
+ *(uint64_t*)0x200000c0 = 0;
+ *(uint64_t*)0x200000c8 = 0;
+ *(uint64_t*)0x200000d0 = 0;
+ *(uint64_t*)0x200000d8 = 0;
+ *(uint64_t*)0x200000e0 = 0;
+ *(uint64_t*)0x200000e8 = 0;
+ *(uint64_t*)0x200000f0 = 0;
+ *(uint64_t*)0x200000f8 = 0;
+ *(uint64_t*)0x20000140 = 0x1b7;
+ *(uint64_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0;
+ *(uint64_t*)0x20000158 = 0;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint64_t*)0x20000170 = 0;
+ *(uint64_t*)0x20000178 = 0;
+ syscall(__NR_pselect6, 0x40ul, 0x200000c0ul, 0ul, 0x20000140ul, 0ul, 0ul);
+ break;
+ case 6:
+ *(uint64_t*)0x20000000 = 0x20000500;
+ *(uint64_t*)0x20000008 = 0x3528a9c0;
+ syscall(__NR_vmsplice, r[0], 0x20000000ul, 1ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/857b4cdfac73d5ae10e85a3f30cf370529df0d37.c b/syzkaller-repros/linux/857b4cdfac73d5ae10e85a3f30cf370529df0d37.c
new file mode 100644
index 0000000..4028faa
--- /dev/null
+++ b/syzkaller-repros/linux/857b4cdfac73d5ae10e85a3f30cf370529df0d37.c
@@ -0,0 +1,237 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+#ifndef __NR_io_uring_setup
+#define __NR_io_uring_setup 425
+#endif
+
+void execute_one(void)
+{
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0x357;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint64_t*)0x20000088 = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint64_t*)0x200000b0 = 0;
+ syscall(__NR_io_uring_setup, 0xf66, 0x20000040);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/87d3bf6296c859d92186a158d189fb1b4119c59e.c b/syzkaller-repros/linux/87d3bf6296c859d92186a158d189fb1b4119c59e.c
new file mode 100644
index 0000000..6209884
--- /dev/null
+++ b/syzkaller-repros/linux/87d3bf6296c859d92186a158d189fb1b4119c59e.c
@@ -0,0 +1,503 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+void execute_one(void)
+{
+ *(uint8_t*)0x200018c0 = 0x12;
+ *(uint8_t*)0x200018c1 = 1;
+ *(uint16_t*)0x200018c2 = 0;
+ *(uint8_t*)0x200018c4 = 0x30;
+ *(uint8_t*)0x200018c5 = 0x7c;
+ *(uint8_t*)0x200018c6 = 0x54;
+ *(uint8_t*)0x200018c7 = 8;
+ *(uint16_t*)0x200018c8 = 0x586;
+ *(uint16_t*)0x200018ca = 0x3413;
+ *(uint16_t*)0x200018cc = 0xa046;
+ *(uint8_t*)0x200018ce = 0;
+ *(uint8_t*)0x200018cf = 0;
+ *(uint8_t*)0x200018d0 = 0;
+ *(uint8_t*)0x200018d1 = 1;
+ *(uint8_t*)0x200018d2 = 9;
+ *(uint8_t*)0x200018d3 = 2;
+ *(uint16_t*)0x200018d4 = 0x4e;
+ *(uint8_t*)0x200018d6 = 1;
+ *(uint8_t*)0x200018d7 = 0;
+ *(uint8_t*)0x200018d8 = 0x81;
+ *(uint8_t*)0x200018d9 = 0;
+ *(uint8_t*)0x200018da = 0;
+ *(uint8_t*)0x200018db = 9;
+ *(uint8_t*)0x200018dc = 4;
+ *(uint8_t*)0x200018dd = 0x9b;
+ *(uint8_t*)0x200018de = 0;
+ *(uint8_t*)0x200018df = 6;
+ *(uint8_t*)0x200018e0 = 0xbe;
+ *(uint8_t*)0x200018e1 = 0x43;
+ *(uint8_t*)0x200018e2 = 0x40;
+ *(uint8_t*)0x200018e3 = 0;
+ *(uint8_t*)0x200018e4 = 7;
+ *(uint8_t*)0x200018e5 = 5;
+ *(uint8_t*)0x200018e6 = 4;
+ *(uint8_t*)0x200018e7 = 0xc;
+ *(uint16_t*)0x200018e8 = 0x800;
+ *(uint8_t*)0x200018ea = 0x1f;
+ *(uint8_t*)0x200018eb = 1;
+ *(uint8_t*)0x200018ec = 5;
+ *(uint8_t*)0x200018ed = 7;
+ *(uint8_t*)0x200018ee = 5;
+ *(uint8_t*)0x200018ef = 3;
+ *(uint8_t*)0x200018f0 = 0x13;
+ *(uint16_t*)0x200018f1 = 6;
+ *(uint8_t*)0x200018f3 = 7;
+ *(uint8_t*)0x200018f4 = 0x80;
+ *(uint8_t*)0x200018f5 = 1;
+ *(uint8_t*)0x200018f6 = 7;
+ *(uint8_t*)0x200018f7 = 5;
+ *(uint8_t*)0x200018f8 = 6;
+ *(uint8_t*)0x200018f9 = 0xc;
+ *(uint16_t*)0x200018fa = 0x7f;
+ *(uint8_t*)0x200018fc = 0x81;
+ *(uint8_t*)0x200018fd = -1;
+ *(uint8_t*)0x200018fe = 4;
+ *(uint8_t*)0x200018ff = 2;
+ *(uint8_t*)0x20001900 = 0;
+ *(uint8_t*)0x20001901 = 2;
+ *(uint8_t*)0x20001902 = 6;
+ *(uint8_t*)0x20001903 = 7;
+ *(uint8_t*)0x20001904 = 5;
+ *(uint8_t*)0x20001905 = 0x22;
+ *(uint8_t*)0x20001906 = 0;
+ *(uint16_t*)0x20001907 = 1;
+ *(uint8_t*)0x20001909 = 0xe4;
+ *(uint8_t*)0x2000190a = 1;
+ *(uint8_t*)0x2000190b = 0x37;
+ *(uint8_t*)0x2000190c = 7;
+ *(uint8_t*)0x2000190d = 5;
+ *(uint8_t*)0x2000190e = 6;
+ *(uint8_t*)0x2000190f = 6;
+ *(uint16_t*)0x20001910 = 0xeffd;
+ *(uint8_t*)0x20001912 = 8;
+ *(uint8_t*)0x20001913 = 1;
+ *(uint8_t*)0x20001914 = 1;
+ *(uint8_t*)0x20001915 = 2;
+ *(uint8_t*)0x20001916 = 0x2b;
+ *(uint8_t*)0x20001917 = 7;
+ *(uint8_t*)0x20001918 = 5;
+ *(uint8_t*)0x20001919 = 3;
+ *(uint8_t*)0x2000191a = 0;
+ *(uint16_t*)0x2000191b = 0xda;
+ *(uint8_t*)0x2000191d = 0x7e;
+ *(uint8_t*)0x2000191e = 8;
+ *(uint8_t*)0x2000191f = 5;
+ syz_usb_connect(2, 0x60, 0x200018c0, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/8a67302e1043ae88b584e8f44db150de4b3e9e46.c b/syzkaller-repros/linux/8a67302e1043ae88b584e8f44db150de4b3e9e46.c
new file mode 100644
index 0000000..bd4ea10
--- /dev/null
+++ b/syzkaller-repros/linux/8a67302e1043ae88b584e8f44db150de4b3e9e46.c
@@ -0,0 +1,161 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+}
+
+#define SYZ_HAVE_RESET_TEST 1
+static void reset_test()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ reset_test();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ long res = 0;
+ memcpy((void*)0x200000c0, "/dev/video#", 12);
+ res = syz_open_dev(0x200000c0, 4, 0x202);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_write, r[0], 0x20000040, 0);
+ syscall(__NR_mmap, 0x20ffd000, 0x3000, 3, 0x11, r[0], 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/8ab5d21faf80f1ee44314d64c330e91676c48d0c.c b/syzkaller-repros/linux/8ab5d21faf80f1ee44314d64c330e91676c48d0c.c
new file mode 100644
index 0000000..38b597a
--- /dev/null
+++ b/syzkaller-repros/linux/8ab5d21faf80f1ee44314d64c330e91676c48d0c.c
@@ -0,0 +1,140 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x64;
+ *(uint8_t*)0x20000004 = 2;
+ *(uint8_t*)0x20000005 = 6;
+ *(uint16_t*)0x20000006 = 1;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 0;
+ *(uint16_t*)0x20000012 = htobe16(0);
+ *(uint16_t*)0x20000014 = 0xe;
+ *(uint16_t*)0x20000016 = 3;
+ memcpy((void*)0x20000018, "bitmap:ip\000", 10);
+ *(uint16_t*)0x20000024 = 9;
+ *(uint16_t*)0x20000026 = 2;
+ memcpy((void*)0x20000028, "syz1\000", 5);
+ *(uint16_t*)0x20000030 = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x20000032, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000033, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000033, 1, 7, 1);
+ *(uint16_t*)0x20000034 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000036, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000037, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000037, 1, 7, 1);
+ *(uint16_t*)0x20000038 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000003a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000003b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000003b, 0, 7, 1);
+ *(uint32_t*)0x2000003c = htobe32(3);
+ *(uint16_t*)0x20000040 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000042, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000043, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000043, 1, 7, 1);
+ *(uint16_t*)0x20000044 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000046, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000047, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000047, 0, 7, 1);
+ *(uint32_t*)0x20000048 = htobe32(0);
+ *(uint16_t*)0x2000004c = 5;
+ *(uint16_t*)0x2000004e = 1;
+ *(uint8_t*)0x20000050 = 7;
+ *(uint16_t*)0x20000054 = 5;
+ *(uint16_t*)0x20000056 = 4;
+ *(uint8_t*)0x20000058 = 0;
+ *(uint16_t*)0x2000005c = 5;
+ *(uint16_t*)0x2000005e = 5;
+ *(uint8_t*)0x20000060 = 2;
+ *(uint64_t*)0x200002c8 = 0x64;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ syscall(__NR_socket, 0xaul, 3ul, 0x3aul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint64_t*)0x20000090 = 0x20000040;
+ *(uint64_t*)0x20000040 = 0x200000c0;
+ *(uint32_t*)0x200000c0 = 0x44;
+ *(uint8_t*)0x200000c4 = 0xa;
+ *(uint8_t*)0x200000c5 = 6;
+ *(uint16_t*)0x200000c6 = 0x301;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint8_t*)0x200000d0 = 0;
+ *(uint8_t*)0x200000d1 = 0;
+ *(uint16_t*)0x200000d2 = htobe16(0);
+ *(uint16_t*)0x200000d4 = 9;
+ *(uint16_t*)0x200000d6 = 2;
+ memcpy((void*)0x200000d8, "syz1\000", 5);
+ *(uint16_t*)0x200000e0 = 5;
+ *(uint16_t*)0x200000e2 = 1;
+ *(uint8_t*)0x200000e4 = 7;
+ *(uint16_t*)0x200000e8 = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x200000ea, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000eb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000eb, 1, 7, 1);
+ *(uint16_t*)0x200000ec = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000ee, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000ef, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000ef, 1, 7, 1);
+ *(uint16_t*)0x200000f0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000f2, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000f3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000f3, 0, 7, 1);
+ *(uint32_t*)0x200000f4 = htobe32(0);
+ *(uint16_t*)0x200000f8 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000fa, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000fb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000fb, 1, 7, 1);
+ *(uint16_t*)0x200000fc = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000fe, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000ff, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000ff, 0, 7, 1);
+ *(uint32_t*)0x20000100 = htobe32(0);
+ *(uint64_t*)0x20000048 = 0x44;
+ *(uint64_t*)0x20000098 = 1;
+ *(uint64_t*)0x200000a0 = 0;
+ *(uint64_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000080ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/8afcfa289eecd61a16a7b15a7d5b8fd31b9500cb.c b/syzkaller-repros/linux/8afcfa289eecd61a16a7b15a7d5b8fd31b9500cb.c
new file mode 100644
index 0000000..d77c69a
--- /dev/null
+++ b/syzkaller-repros/linux/8afcfa289eecd61a16a7b15a7d5b8fd31b9500cb.c
@@ -0,0 +1,64 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ long res = 0;
+ memcpy((void*)0x20000100, "/dev/video#", 12);
+ res = syz_open_dev(0x20000100, 0x3f, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 1;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint64_t*)0x20000058 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x980914;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint64_t*)0x2000000c = 0x20000080;
+ *(uint8_t*)0x20000080 = 0;
+ syscall(__NR_ioctl, r[0], 0xc0205648, 0x20000040);
+ memcpy((void*)0x20000280, "/dev/video#", 12);
+ res = syz_open_dev(0x20000280, 3, 0);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_read, r[1], 0x200002c0, 0xba);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/8b36a396ec6f779c412e50ecb320b66b67569099.c b/syzkaller-repros/linux/8b36a396ec6f779c412e50ecb320b66b67569099.c
new file mode 100644
index 0000000..9e10a25
--- /dev/null
+++ b/syzkaller-repros/linux/8b36a396ec6f779c412e50ecb320b66b67569099.c
@@ -0,0 +1,303 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/loop.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct fs_image_segment {
+ void* data;
+ uintptr_t size;
+ uintptr_t offset;
+};
+
+#define IMAGE_MAX_SEGMENTS 4096
+#define IMAGE_MAX_SIZE (129 << 20)
+
+#define sys_memfd_create 319
+
+static unsigned long fs_image_segment_check(unsigned long size,
+ unsigned long nsegs, long segments)
+{
+ unsigned long i;
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ if (nsegs > IMAGE_MAX_SEGMENTS)
+ nsegs = IMAGE_MAX_SEGMENTS;
+ for (i = 0; i < nsegs; i++) {
+ if (segs[i].size > IMAGE_MAX_SIZE)
+ segs[i].size = IMAGE_MAX_SIZE;
+ segs[i].offset %= IMAGE_MAX_SIZE;
+ if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
+ segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
+ if (size < segs[i].offset + segs[i].offset)
+ size = segs[i].offset + segs[i].offset;
+ }
+ if (size > IMAGE_MAX_SIZE)
+ size = IMAGE_MAX_SIZE;
+ return size;
+}
+
+static long syz_mount_image(volatile long fsarg, volatile long dir,
+ volatile unsigned long size,
+ volatile unsigned long nsegs,
+ volatile long segments, volatile long flags,
+ volatile long optsarg)
+{
+ char loopname[64], fs[32], opts[256];
+ int loopfd, err = 0, res = -1;
+ unsigned long i;
+
+ size = fs_image_segment_check(size, nsegs, segments);
+ int memfd = syscall(sys_memfd_create, "syz_mount_image", 0);
+ if (memfd == -1) {
+ err = errno;
+ goto error;
+ }
+ if (ftruncate(memfd, size)) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ for (i = 0; i < nsegs; i++) {
+ struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+ int res1 = 0;
+ res1 = pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset);
+ if (res1 < 0) {
+ }
+ }
+ snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
+ loopfd = open(loopname, O_RDWR);
+ if (loopfd == -1) {
+ err = errno;
+ goto error_close_memfd;
+ }
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ if (errno != EBUSY) {
+ err = errno;
+ goto error_close_loop;
+ }
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ usleep(1000);
+ if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+ err = errno;
+ goto error_close_loop;
+ }
+ }
+ mkdir((char*)dir, 0777);
+ memset(fs, 0, sizeof(fs));
+ strncpy(fs, (char*)fsarg, sizeof(fs) - 1);
+ memset(opts, 0, sizeof(opts));
+ strncpy(opts, (char*)optsarg, sizeof(opts) - 32);
+ if (strcmp(fs, "iso9660") == 0) {
+ flags |= MS_RDONLY;
+ } else if (strncmp(fs, "ext", 3) == 0) {
+ if (strstr(opts, "errors=panic") || strstr(opts, "errors=remount-ro") == 0)
+ strcat(opts, ",errors=continue");
+ } else if (strcmp(fs, "xfs") == 0) {
+ strcat(opts, ",nouuid");
+ }
+ if (mount(loopname, (char*)dir, fs, flags, opts)) {
+ err = errno;
+ goto error_clear_loop;
+ }
+ res = 0;
+error_clear_loop:
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+error_close_loop:
+ close(loopfd);
+error_close_memfd:
+ close(memfd);
+error:
+ errno = err;
+ return res;
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void reset_loop()
+{
+ char buf[64];
+ snprintf(buf, sizeof(buf), "/dev/loop%llu", procid);
+ int loopfd = open(buf, O_RDWR);
+ if (loopfd != -1) {
+ ioctl(loopfd, LOOP_CLR_FD, 0);
+ close(loopfd);
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+void execute_one(void)
+{
+ inject_fault(16);
+ syz_mount_image(0, 0, 0, 0, 0, 0, 0);
+}
+int main(void)
+{
+ inject_fault(16);
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/8c1106a7287dc1cdbfc455097ddfab8faeb5ffcb.c b/syzkaller-repros/linux/8c1106a7287dc1cdbfc455097ddfab8faeb5ffcb.c
new file mode 100644
index 0000000..a0899cd
--- /dev/null
+++ b/syzkaller-repros/linux/8c1106a7287dc1cdbfc455097ddfab8faeb5ffcb.c
@@ -0,0 +1,737 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 6; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ NONFAILING(memcpy((void*)0x20000240, "/dev/input/event#\000", 18));
+ syz_open_dev(0x20000240, 0xa68, 0x100000000000000);
+ break;
+ case 1:
+ NONFAILING(memcpy((void*)0x20000140, "/dev/uinput\000", 12));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000140ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ NONFAILING(*(uint16_t*)0x20000040 = -1);
+ NONFAILING(*(uint16_t*)0x20000042 = 0);
+ NONFAILING(*(uint16_t*)0x20000044 = 5);
+ NONFAILING(*(uint16_t*)0x20000046 = 0xfc01);
+ NONFAILING(memcpy(
+ (void*)0x20000048,
+ "s\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\002\000\000\000\000\000\000\000\000\000\'\214\355\221\2135j`"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"
+ "\005\377\377\377\000\000\000\000",
+ 80));
+ NONFAILING(*(uint32_t*)0x20000098 = 0);
+ syscall(__NR_ioctl, r[0], 0x405c5503ul, 0x20000040ul);
+ break;
+ case 3:
+ syscall(__NR_ioctl, r[0], 0x5501ul, 0ul);
+ break;
+ case 4:
+ syscall(__NR_ioctl, -1, 0x8914ul, 0ul);
+ break;
+ case 5:
+ syscall(__NR_setsockopt, -1, 0x21ul, 0xful, 0ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/8d186fae388cadf8b664d5d74214851c2855d2db.c b/syzkaller-repros/linux/8d186fae388cadf8b664d5d74214851c2855d2db.c
new file mode 100644
index 0000000..991b0b3
--- /dev/null
+++ b/syzkaller-repros/linux/8d186fae388cadf8b664d5d74214851c2855d2db.c
@@ -0,0 +1,223 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/ptmx\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000000, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0xf;
+ syscall(__NR_ioctl, r[0], 0x5423, 0x20000040);
+ syscall(__NR_ioctl, r[0], 0x400455c8, 0);
+ *(uint32_t*)0x20000100 = 2;
+ syscall(__NR_ioctl, r[0], 0x5412, 0x20000100);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/917103403545122e58fa7f05f5e27e26d1b44b4e.c b/syzkaller-repros/linux/917103403545122e58fa7f05f5e27e26d1b44b4e.c
new file mode 100644
index 0000000..dc6e5da
--- /dev/null
+++ b/syzkaller-repros/linux/917103403545122e58fa7f05f5e27e26d1b44b4e.c
@@ -0,0 +1,439 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_init_net_socket(volatile long domain, volatile long type,
+ volatile long proto)
+{
+ return syscall(__NR_socket, domain, type, proto);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_init_net_socket(0x1f, 1, 3);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20000000 = 0x1f;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint8_t*)0x20000004 = 0;
+ *(uint8_t*)0x20000005 = 0;
+ *(uint8_t*)0x20000006 = 0;
+ *(uint8_t*)0x20000007 = 0;
+ *(uint8_t*)0x20000008 = 4;
+ *(uint8_t*)0x20000009 = 0;
+ *(uint16_t*)0x2000000a = 0;
+ *(uint8_t*)0x2000000c = 0;
+ syscall(__NR_connect, r[0], 0x20000000ul, 0x32ul);
+ *(uint8_t*)0x20000100 = 0xfe;
+ *(uint8_t*)0x20000101 = 0x80;
+ *(uint8_t*)0x20000102 = 0;
+ *(uint8_t*)0x20000103 = 0;
+ *(uint8_t*)0x20000104 = 0;
+ *(uint8_t*)0x20000105 = 0;
+ *(uint8_t*)0x20000106 = 0;
+ *(uint8_t*)0x20000107 = 0;
+ *(uint8_t*)0x20000108 = 0;
+ *(uint8_t*)0x20000109 = 0;
+ *(uint8_t*)0x2000010a = 0;
+ *(uint8_t*)0x2000010b = 0;
+ *(uint8_t*)0x2000010c = 0;
+ *(uint8_t*)0x2000010d = 0;
+ *(uint8_t*)0x2000010e = 0;
+ *(uint8_t*)0x2000010f = 0;
+ *(uint32_t*)0x20000110 = 0;
+ *(uint8_t*)0x20000114 = 4;
+ *(uint8_t*)0x20000115 = 0;
+ *(uint16_t*)0x20000116 = 0;
+ *(uint16_t*)0x20000118 = 0;
+ *(uint16_t*)0x2000011a = 0;
+ *(uint32_t*)0x2000011c = 0;
+ syscall(__NR_getsockopt, -1, 0x29ul, 0x20ul, 0x20000100ul, 0ul);
+ res = syz_init_net_socket(0x1f, 1, 3);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_ioctl, r[1], 0x400452c8ul, 0x20000100ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/938eac2e752cc83e060a5c9fc3be0e83edeb687b.c b/syzkaller-repros/linux/938eac2e752cc83e060a5c9fc3be0e83edeb687b.c
new file mode 100644
index 0000000..8130316
--- /dev/null
+++ b/syzkaller-repros/linux/938eac2e752cc83e060a5c9fc3be0e83edeb687b.c
@@ -0,0 +1,431 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ if (pthread_create(&th, &attr, fn, arg))
+ exit(1);
+ pthread_attr_destroy(&attr);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+}
+
+#define SYZ_HAVE_RESET_TEST 1
+static void reset_test()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 15; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ reset_test();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ NONFAILING(*(uint16_t*)0x20000140 = 0xcc);
+ NONFAILING(*(uint8_t*)0x20000142 = 1);
+ NONFAILING(*(uint8_t*)0x20000143 = 2);
+ NONFAILING(*(uint32_t*)0x20000144 = 0x34a);
+ NONFAILING(*(uint32_t*)0x20000148 = 0xad);
+ NONFAILING(*(uint32_t*)0x2000014c = 9);
+ NONFAILING(*(uint32_t*)0x20000150 = 0x164);
+ NONFAILING(*(uint32_t*)0x20000154 = 0x101);
+ NONFAILING(*(uint32_t*)0x20000158 = 0);
+ NONFAILING(*(uint32_t*)0x2000015c = 0);
+ NONFAILING(memcpy(
+ (void*)0x20000160,
+ "\x81\xd8\x96\x96\xee\xe6\x58\xc4\x53\x46\xf5\x30\xa4\xbe\x5e\x87\x71"
+ "\x67\x1c\x2f\x8d\xe5\x26\x06\x85\xdf\xa2\x07\x53\xed\x31\xbe\x76\xc2"
+ "\x06\x9b\xc3\x77\x57\xbc\xbc\x2f\xb0\x42\x47\xf2\xd4\xaf\x99\x57\x80"
+ "\x0a\x0f\x82\x6e\x4a\x6c\xd7\x0e\xcc\xf4\x13\xe5\xc7\xa0\xba\x3a\x89"
+ "\xa1\xb5\x4f\x03\xe2\x24\x8b\x66\xf1\x4c\x0d\x89\xe1\x9d\x66\xdf\x3a"
+ "\x38\x36\xb9\xf3\xe5\xec\x7d\xb7\xe0\x34\xa9\xa4\x7d\x8c\xb0\x07\xc1"
+ "\x2f\x12\x6b\xba\x8e\xd4\x2f\x12\x93\x68\x14\xdf\x31\x78\x2d\xa9\x19"
+ "\x2d\x45\x79\x25\x01\xf1\x22\x51\x2b\x8a\x45\x89\xcb\xbd\x52\xe8\x2d"
+ "\x3f\x2d\x1c\xdb\x65\xc7\xe4\x79\xb2\x1f\xfa\xc7\xc4\x8e\xe2\xf0\x7f"
+ "\x8a\x21\xc6\x1c\xda\xbc\xef\xe2\x3d\xb7\xba\x50\x80\x08\x11\x62\xa4"
+ "\x5a\xcf\x10\xc3\xc7\x56\x1f\x37\xa3\x63\x2a\xe4\xfa\xe1\x22\xfe\xeb"
+ "\x78\x20\xb0\x4e\x48\x44\xce\xb6\x6f\x5e\xd1\x06\xbc\x9c\xd0\x4b\xfd"
+ "\x9b\xde\xd5\x79\x5a\xc4\x78\x0f\xe6\x8c\x38\x73\x50\x4d\x3a\x71\x0f"
+ "\xfa\xef\xbd\x51\xff\x40\x1f\x83\xa9\x91\xaf\xff\x74\x53\x9e\x23\x9d"
+ "\x4a\xde\xf1\xb2\xab\xd7\xdf\x45\x68\xd2",
+ 248));
+ syscall(__NR_write, -1, 0x20000140, 0x118);
+ break;
+ case 1:
+ NONFAILING(*(uint32_t*)0x20000080 = 0x7fffffff);
+ NONFAILING(*(uint32_t*)0x20000084 = 0);
+ NONFAILING(*(uint32_t*)0x20000088 = 4);
+ NONFAILING(*(uint32_t*)0x2000008c = 0);
+ NONFAILING(*(uint32_t*)0x20000090 = 0);
+ syscall(__NR_ioctl, -1, 0xc0145608, 0x20000080);
+ break;
+ case 2:
+ NONFAILING(memcpy((void*)0x20000140, "/dev/video#", 12));
+ res = syz_open_dev(0x20000140, 0x40, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 3:
+ NONFAILING(*(uint32_t*)0x20000040 = 2);
+ NONFAILING(memcpy(
+ (void*)0x20000048,
+ "\x2a\x85\x5c\xa4\xb2\x5f\x9b\x60\xdd\x9d\xc4\xe2\x11\x2d\x34\xf0\x8f"
+ "\x4d\x6f\x33\x5d\xea\x14\xd8\xb7\x10\xb8\x13\xa5\x05\x4b\x9e\x6c\xe2"
+ "\x8d\x85\x98\xb1\x1f\x92\x28\xcb\xea\x47\x33\x1e\xfd\xde\xa5\xfa\x98"
+ "\x0a\x78\xd1\x7e\xab\xb9\x78\xf1\x83\xef\x21\xcf\x70\x60\x77\xd1\xe2"
+ "\xb5\x16\x6e\x65\x9a\xfa\xa0\xfa\x55\x95\x94\x66\x4d\x34\x03\x12\x65"
+ "\xea\x82\x4f\x40\x84\x3c\x97\x80\x1c\x6a\x6a\x20\x0b\xe4\x66\x8c\xb3"
+ "\x3d\x4f\x95\x6c\xf8\xfb\x24\xdd\x10\x2a\x35\xd3\x67\x30\xaa\xa6\xd3"
+ "\x9f\x34\xe4\xbb\x4b\x1b\xd5\xd0\x97\x2e\xf3\xe1\x88\x8b\x78\xc5\x02"
+ "\x32\x82\xf2\x3c\xc0\xac\xb7\x81\x93\xe9\x70\x09\x08\x3b\x03\x34\x7a"
+ "\x52\x63\xab\xca\x78\x41\x86\xec\x57\xf3\x5a\x45\x30\x83\x6c\x9f\xc9"
+ "\x56\xa5\x4f\x47\x76\x01\x0c\xd6\x94\xd3\xe4\xcf\x25\xf4\x45\x0c\xa2"
+ "\xcd\x05\x97\x90\x23\xe6\x6f\x9a\x2a\x64\xda\xe7\x50",
+ 200));
+ syscall(__NR_ioctl, r[0], 0xc0d05605, 0x20000040);
+ break;
+ case 4:
+ NONFAILING(memcpy((void*)0x20000000, "/dev/video#", 12));
+ res = syz_open_dev(0x20000000, 4, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 5:
+ NONFAILING(*(uint32_t*)0x20000100 = 5);
+ NONFAILING(*(uint32_t*)0x20000104 = 2);
+ NONFAILING(*(uint32_t*)0x20000108 = 1);
+ NONFAILING(*(uint32_t*)0x2000010c = 0);
+ NONFAILING(*(uint32_t*)0x20000110 = 0);
+ syscall(__NR_ioctl, r[1], 0xc0145608, 0x20000100);
+ break;
+ case 6:
+ syscall(__NR_ioctl, r[1], 0x8008563f, 0x20000040);
+ break;
+ case 7:
+ NONFAILING(memcpy((void*)0x20000080, "/dev/video#", 12));
+ syz_open_dev(0x20000080, 7, 0x22000);
+ break;
+ case 8:
+ syscall(__NR_close, -1);
+ break;
+ case 9:
+ NONFAILING(*(uint32_t*)0x20000040 = -1);
+ NONFAILING(*(uint16_t*)0x20000044 = 0x90);
+ NONFAILING(*(uint16_t*)0x20000046 = 0);
+ syscall(__NR_poll, 0x20000040, 1, 3);
+ break;
+ case 10:
+ NONFAILING(memcpy((void*)0x20000040, "/dev/v4l-subdev#", 17));
+ res = syz_open_dev(0x20000040, 0x92, 0x282101);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 11:
+ NONFAILING(*(uint32_t*)0x200000c0 = 2);
+ NONFAILING(*(uint32_t*)0x200000c4 = 4);
+ NONFAILING(*(uint32_t*)0x200000c8 = 1);
+ NONFAILING(*(uint32_t*)0x200000cc = 0);
+ NONFAILING(*(uint32_t*)0x200000d0 = 0);
+ syscall(__NR_ioctl, r[2], 0xc0145608, 0x200000c0);
+ break;
+ case 12:
+ syscall(__NR_close, -1);
+ break;
+ case 13:
+ NONFAILING(*(uint32_t*)0x20000040 = 7);
+ NONFAILING(memcpy(
+ (void*)0x20000044,
+ "\xb2\xcc\x2b\x8c\xfb\x25\x26\xba\x11\xf5\x44\x76\x92\xd6\xb9\xff\xb0"
+ "\xff\xf0\xd9\x77\xbc\x9e\x76\x8f\xe4\xe8\x7c\x1f\x2f\x09\x70",
+ 32));
+ NONFAILING(*(uint32_t*)0x20000064 = 8);
+ NONFAILING(*(uint64_t*)0x20000068 = 1);
+ NONFAILING(*(uint64_t*)0x20000070 = 7);
+ syscall(__NR_ioctl, -1, 0x4038564f, 0x20000040);
+ break;
+ case 14:
+ syscall(__NR_write, -1, 0x20001580, 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/939673fcc99d8c8ac52a3d4d9862bd1748bab317.c b/syzkaller-repros/linux/939673fcc99d8c8ac52a3d4d9862bd1748bab317.c
new file mode 100644
index 0000000..295d6fc
--- /dev/null
+++ b/syzkaller-repros/linux/939673fcc99d8c8ac52a3d4d9862bd1748bab317.c
@@ -0,0 +1,317 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x20000100 = 2;
+ *(uint8_t*)0x20000101 = 2;
+ *(uint16_t*)0x20000102 = 0;
+ *(uint16_t*)0x20000104 = 0;
+ *(uint16_t*)0x20000106 = 0;
+ *(uint16_t*)0x20000108 = 0;
+ *(uint16_t*)0x2000010a = 0;
+ syscall(__NR_ioctl, r[0], 0x541cul, 0x20000100ul);
+ res = syz_open_dev(0xc, 4, 0x14);
+ if (res != -1)
+ r[1] = res;
+ memcpy(
+ (void*)0x20000100,
+ "\x82\xaf\xa5\x1d\x23\x2b\x58\x78\x3c\xd2\x55\x7c\x70\xa9\x3d\xf1\xbd\xf3"
+ "\x7b\x3d\x42\x89\xe8\x85\xa1\xe9\xf2\x54\x4b\x74\x17\x96\xf4\xdb\xc9\x81"
+ "\xec\x3d\x8e\xf5\x96\x02\x52\x2d\xf4\xdc\x34\xa4\x48\xd5\x19\x5a\x10\x61"
+ "\xba\xdd\x08\xfd\xd0\x53\x78\xb7\x92\x9a\x3b\xcf\xd8\x82\x71\x15\xd3\x20"
+ "\xaf\x9b\x81\xe8\xc8\x18\xcb\x85\x63\x59\xbe\x8b\xca\x3e\x52\x1e\x41\x6e"
+ "\x66\x8c\xd3\xdb\x43\x8a\x44\xe9\x98\x8e\x51\xac\x2e\xdc\x3d\xe3\x4d\xbc"
+ "\x15\x29\xc6\x94\x10\x10\x95\x93\x94\x49\x28\x3d",
+ 120);
+ syscall(__NR_ioctl, r[1], 0x4b61ul, 0x20000100ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/944b6e7cbd6c173d7f8dffd5e1715c2e25c71d5c.c b/syzkaller-repros/linux/944b6e7cbd6c173d7f8dffd5e1715c2e25c71d5c.c
new file mode 100644
index 0000000..799bdf5
--- /dev/null
+++ b/syzkaller-repros/linux/944b6e7cbd6c173d7f8dffd5e1715c2e25c71d5c.c
@@ -0,0 +1,204 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1)
+
+#define BITMASK_LEN_OFF(type, bf_off, bf_len) \
+ (type)(BITMASK_LEN(type, (bf_len)) << (bf_off))
+
+#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \
+ if ((bf_off) == 0 && (bf_len) == 0) { \
+ *(type*)(addr) = (type)(val); \
+ } else { \
+ type new_val = *(type*)(addr); \
+ new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \
+ new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \
+ *(type*)(addr) = new_val; \
+ }
+
+struct csum_inet {
+ uint32_t acc;
+};
+
+static void csum_inet_init(struct csum_inet* csum)
+{
+ csum->acc = 0;
+}
+
+static void csum_inet_update(struct csum_inet* csum,
+ const uint8_t* data, size_t length)
+{
+ if (length == 0)
+ return;
+
+ size_t i;
+ for (i = 0; i < length - 1; i += 2)
+ csum->acc += *(uint16_t*)&data[i];
+
+ if (length & 1)
+ csum->acc += (uint16_t)data[length - 1];
+
+ while (csum->acc > 0xffff)
+ csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16);
+}
+
+static uint16_t csum_inet_digest(struct csum_inet* csum)
+{
+ return ~csum->acc;
+}
+
+long r[130];
+void loop()
+{
+ memset(r, -1, sizeof(r));
+ r[0] = syscall(__NR_mmap, 0x20000000ul, 0xfff000ul, 0x3ul, 0x32ul,
+ 0xfffffffffffffffful, 0x0ul);
+ r[1] = syscall(__NR_socket, 0x2ul, 0x3ul, 0x4ul);
+ *(uint32_t*)0x20000000 = (uint32_t)0x0;
+ *(uint8_t*)0x20000010 = (uint8_t)0xac;
+ *(uint8_t*)0x20000011 = (uint8_t)0x14;
+ *(uint8_t*)0x20000012 = (uint8_t)0x0;
+ *(uint8_t*)0x20000013 = (uint8_t)0xbb;
+ *(uint16_t*)0x20000020 = (uint16_t)0x204e;
+ *(uint16_t*)0x20000022 = (uint16_t)0x0;
+ *(uint16_t*)0x20000024 = (uint16_t)0x204e;
+ *(uint16_t*)0x20000026 = (uint16_t)0x0;
+ *(uint16_t*)0x20000028 = (uint16_t)0x2;
+ *(uint8_t*)0x2000002a = (uint8_t)0x0;
+ *(uint8_t*)0x2000002b = (uint8_t)0x0;
+ *(uint8_t*)0x2000002c = (uint8_t)0x0;
+ *(uint32_t*)0x20000030 = (uint32_t)0x0;
+ *(uint32_t*)0x20000034 = (uint32_t)0x0;
+ *(uint64_t*)0x20000038 = (uint64_t)0x0;
+ *(uint64_t*)0x20000040 = (uint64_t)0x0;
+ *(uint64_t*)0x20000048 = (uint64_t)0xfffffffffffffffc;
+ *(uint64_t*)0x20000050 = (uint64_t)0x0;
+ *(uint64_t*)0x20000058 = (uint64_t)0x0;
+ *(uint64_t*)0x20000060 = (uint64_t)0x0;
+ *(uint64_t*)0x20000068 = (uint64_t)0x0;
+ *(uint64_t*)0x20000070 = (uint64_t)0x0;
+ *(uint64_t*)0x20000078 = (uint64_t)0x0;
+ *(uint64_t*)0x20000080 = (uint64_t)0x0;
+ *(uint64_t*)0x20000088 = (uint64_t)0x0;
+ *(uint64_t*)0x20000090 = (uint64_t)0x0;
+ *(uint32_t*)0x20000098 = (uint32_t)0x0;
+ *(uint32_t*)0x2000009c = (uint32_t)0x0;
+ *(uint8_t*)0x200000a0 = (uint8_t)0x1;
+ *(uint8_t*)0x200000a1 = (uint8_t)0x0;
+ *(uint8_t*)0x200000a2 = (uint8_t)0x0;
+ *(uint8_t*)0x200000a3 = (uint8_t)0x0;
+ *(uint64_t*)0x200000a8 = (uint64_t)0x0;
+ *(uint64_t*)0x200000b0 = (uint64_t)0x100000000000000;
+ *(uint32_t*)0x200000b8 = (uint32_t)0x0;
+ *(uint8_t*)0x200000bc = (uint8_t)0x81;
+ *(uint16_t*)0x200000c0 = (uint16_t)0xa;
+ *(uint64_t*)0x200000c4 = (uint64_t)0x0;
+ *(uint64_t*)0x200000cc = (uint64_t)0x100000000000000;
+ *(uint32_t*)0x200000d4 = (uint32_t)0x8000000;
+ *(uint8_t*)0x200000d8 = (uint8_t)0x0;
+ *(uint8_t*)0x200000d9 = (uint8_t)0x0;
+ *(uint8_t*)0x200000da = (uint8_t)0x0;
+ *(uint32_t*)0x200000dc = (uint32_t)0x0;
+ *(uint32_t*)0x200000e0 = (uint32_t)0x0;
+ *(uint32_t*)0x200000e4 = (uint32_t)0x0;
+ r[49] = syscall(__NR_setsockopt, r[1], 0x0ul, 0x11ul, 0x20000000ul,
+ 0xe8ul);
+ *(uint16_t*)0x2000e000 = (uint16_t)0x2;
+ *(uint16_t*)0x2000e002 = (uint16_t)0x204e;
+ *(uint8_t*)0x2000e004 = (uint8_t)0xac;
+ *(uint8_t*)0x2000e005 = (uint8_t)0x14;
+ *(uint8_t*)0x2000e006 = (uint8_t)0x0;
+ *(uint8_t*)0x2000e007 = (uint8_t)0xaa;
+ *(uint8_t*)0x2000e008 = (uint8_t)0x0;
+ *(uint8_t*)0x2000e009 = (uint8_t)0x0;
+ *(uint8_t*)0x2000e00a = (uint8_t)0x0;
+ *(uint8_t*)0x2000e00b = (uint8_t)0x0;
+ *(uint8_t*)0x2000e00c = (uint8_t)0x0;
+ *(uint8_t*)0x2000e00d = (uint8_t)0x0;
+ *(uint8_t*)0x2000e00e = (uint8_t)0x0;
+ *(uint8_t*)0x2000e00f = (uint8_t)0x0;
+ r[64] = syscall(__NR_sendto, r[1], 0x2089b000ul, 0x0ul, 0x0ul,
+ 0x2000e000ul, 0x10ul);
+ memcpy((void*)0x20e7e000, "\xef\xa1\x06\xa7\x29\x0c", 6);
+ *(uint8_t*)0x20e7e006 = (uint8_t)0xaa;
+ *(uint8_t*)0x20e7e007 = (uint8_t)0xaa;
+ *(uint8_t*)0x20e7e008 = (uint8_t)0xaa;
+ *(uint8_t*)0x20e7e009 = (uint8_t)0xaa;
+ *(uint8_t*)0x20e7e00a = (uint8_t)0xaa;
+ *(uint8_t*)0x20e7e00b = (uint8_t)0x0;
+ *(uint16_t*)0x20e7e00c = (uint16_t)0x8;
+ STORE_BY_BITMASK(uint8_t, 0x20e7e00e, 0x5, 0, 4);
+ STORE_BY_BITMASK(uint8_t, 0x20e7e00e, 0x4, 4, 4);
+ STORE_BY_BITMASK(uint8_t, 0x20e7e00f, 0x0, 0, 2);
+ STORE_BY_BITMASK(uint8_t, 0x20e7e00f, 0xfffffffffffffffd, 2, 6);
+ *(uint16_t*)0x20e7e010 = (uint16_t)0x5400;
+ *(uint16_t*)0x20e7e012 = (uint16_t)0x6400;
+ *(uint16_t*)0x20e7e014 = (uint16_t)0x0;
+ *(uint8_t*)0x20e7e016 = (uint8_t)0x0;
+ *(uint8_t*)0x20e7e017 = (uint8_t)0x400000000001;
+ *(uint16_t*)0x20e7e018 = (uint16_t)0x0;
+ *(uint8_t*)0x20e7e01a = (uint8_t)0xac;
+ *(uint8_t*)0x20e7e01b = (uint8_t)0x14;
+ *(uint8_t*)0x20e7e01c = (uint8_t)0x0;
+ *(uint8_t*)0x20e7e01d = (uint8_t)0xbb;
+ *(uint8_t*)0x20e7e01e = (uint8_t)0xac;
+ *(uint8_t*)0x20e7e01f = (uint8_t)0x14;
+ *(uint8_t*)0x20e7e020 = (uint8_t)0x0;
+ *(uint8_t*)0x20e7e021 = (uint8_t)0xaa;
+ *(uint8_t*)0x20e7e022 = (uint8_t)0x3;
+ *(uint8_t*)0x20e7e023 = (uint8_t)0x0;
+ *(uint16_t*)0x20e7e024 = (uint16_t)0x0;
+ *(uint8_t*)0x20e7e026 = (uint8_t)0x0;
+ *(uint8_t*)0x20e7e027 = (uint8_t)0x0;
+ *(uint16_t*)0x20e7e028 = (uint16_t)0x0;
+ STORE_BY_BITMASK(uint8_t, 0x20e7e02a, 0xe, 0, 4);
+ STORE_BY_BITMASK(uint8_t, 0x20e7e02a, 0x4, 4, 4);
+ STORE_BY_BITMASK(uint8_t, 0x20e7e02b, 0x6, 0, 2);
+ STORE_BY_BITMASK(uint8_t, 0x20e7e02b, 0x0, 2, 6);
+ *(uint16_t*)0x20e7e02c = (uint16_t)0x0;
+ *(uint16_t*)0x20e7e02e = (uint16_t)0x6400;
+ *(uint16_t*)0x20e7e030 = (uint16_t)0x0;
+ *(uint8_t*)0x20e7e032 = (uint8_t)0x0;
+ *(uint8_t*)0x20e7e033 = (uint8_t)0x6;
+ *(uint16_t*)0x20e7e034 = (uint16_t)0x0;
+ *(uint8_t*)0x20e7e036 = (uint8_t)0xac;
+ *(uint8_t*)0x20e7e037 = (uint8_t)0x14;
+ *(uint8_t*)0x20e7e038 = (uint8_t)0x0;
+ *(uint8_t*)0x20e7e039 = (uint8_t)0xaa;
+ *(uint32_t*)0x20e7e03a = (uint32_t)0x100007f;
+ *(uint8_t*)0x20e7e03e = (uint8_t)0x89;
+ *(uint8_t*)0x20e7e03f = (uint8_t)0x1b;
+ *(uint8_t*)0x20e7e040 = (uint8_t)0x7fffffff;
+ *(uint32_t*)0x20e7e041 = (uint32_t)0x0;
+ *(uint32_t*)0x20e7e045 = (uint32_t)0x10000e0;
+ *(uint32_t*)0x20e7e049 = (uint32_t)0xffffffff;
+ *(uint8_t*)0x20e7e04d = (uint8_t)0xac;
+ *(uint8_t*)0x20e7e04e = (uint8_t)0x14;
+ *(uint8_t*)0x20e7e04f = (uint8_t)0x0;
+ *(uint8_t*)0x20e7e050 = (uint8_t)0xaa;
+ *(uint32_t*)0x20e7e051 = (uint32_t)0x0;
+ *(uint32_t*)0x20e7e055 = (uint32_t)0x10000e0;
+ *(uint8_t*)0x20e7e059 = (uint8_t)0x86;
+ *(uint8_t*)0x20e7e05a = (uint8_t)0x6;
+ *(uint32_t*)0x20e7e05b = (uint32_t)0x0;
+ struct csum_inet csum_127;
+ csum_inet_init(&csum_127);
+ csum_inet_update(&csum_127, (const uint8_t*)0x20e7e022, 64);
+ *(uint16_t*)0x20e7e024 = csum_inet_digest(&csum_127);
+ struct csum_inet csum_128;
+ csum_inet_init(&csum_128);
+ csum_inet_update(&csum_128, (const uint8_t*)0x20e7e00e, 20);
+ *(uint16_t*)0x20e7e018 = csum_inet_digest(&csum_128);
+}
+
+int main()
+{
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/95419b31bfb7783adfd504d4b3ea5f646366e8a9.c b/syzkaller-repros/linux/95419b31bfb7783adfd504d4b3ea5f646366e8a9.c
new file mode 100644
index 0000000..b944bb6
--- /dev/null
+++ b/syzkaller-repros/linux/95419b31bfb7783adfd504d4b3ea5f646366e8a9.c
@@ -0,0 +1,34 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+long r[9];
+void loop()
+{
+ memset(r, -1, sizeof(r));
+ r[0] = syscall(__NR_mmap, 0x20000000ul, 0x8000ul, 0x3ul, 0x32ul,
+ 0xfffffffffffffffful, 0x0ul);
+ *(uint32_t*)0x20007000 = (uint32_t)0xf;
+ *(uint32_t*)0x20007004 = (uint32_t)0x80000001;
+ *(uint32_t*)0x20007008 = (uint32_t)0xffffffffffffff03;
+ *(uint32_t*)0x2000700c = (uint32_t)0x5;
+ *(uint32_t*)0x20007010 = (uint32_t)0x4;
+ *(uint32_t*)0x20007014 = (uint32_t)0xffffffffffffffff;
+ *(uint32_t*)0x20007018 = (uint32_t)0xffffffff80000000;
+ r[8] = syscall(__NR_bpf, 0x0ul, 0x20007000ul, 0x1cul);
+}
+
+int main()
+{
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/98341f62c64fb33877d1996dcce6b2e931c26a2d.c b/syzkaller-repros/linux/98341f62c64fb33877d1996dcce6b2e931c26a2d.c
new file mode 100644
index 0000000..b3ce6ba
--- /dev/null
+++ b/syzkaller-repros/linux/98341f62c64fb33877d1996dcce6b2e931c26a2d.c
@@ -0,0 +1,759 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x2b, 0x801, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20000180 = 2;
+ *(uint16_t*)0x20000182 = htobe16(0);
+ *(uint8_t*)0x20000184 = 0xac;
+ *(uint8_t*)0x20000185 = 0x14;
+ *(uint8_t*)0x20000186 = 0x14;
+ *(uint8_t*)0x20000187 = 0xaa;
+ syscall(__NR_connect, r[0], 0x20000180, 0x10);
+ *(uint16_t*)0x20000040 = 0;
+ *(uint16_t*)0x20000042 = 0x34;
+ memcpy((void*)0x20000044, "\x4f\x41\x98\xfa\x0b\x1e\x34\x8b", 8);
+ memcpy((void*)0x2000004c,
+ "\x20\x1a\x53\x8a\x86\x22\xae\x1b\xeb\x5e\x1b\xa0\xd6\x47\xe4\xec\x9e"
+ "\x6f\x93\xc5\x1e\x5e\xd4\x8a\x65\x2f\x12\x2f\xcc\xe5\x39\xa6",
+ 32);
+ memcpy((void*)0x2000006c, "\x65\x96\xc3\xb8", 4);
+ memcpy((void*)0x20000070, "\x3b\xe0\x90\x7c\xc0\x07\xe1\x7b", 8);
+ syscall(__NR_setsockopt, r[0], 6, 1, 0x20000040, 0x38);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/983b5307cfcad4e74e3dcb1dcacf7f4302aab03b.c b/syzkaller-repros/linux/983b5307cfcad4e74e3dcb1dcacf7f4302aab03b.c
new file mode 100644
index 0000000..415d7fe
--- /dev/null
+++ b/syzkaller-repros/linux/983b5307cfcad4e74e3dcb1dcacf7f4302aab03b.c
@@ -0,0 +1,1146 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 19; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[12] = {0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0x0,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0x0,
+ 0x0,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0xffffffffffffffff,
+ 0x0,
+ 0x0};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_getsockopt, -1, 6ul, 1ul, 0ul, 0ul);
+ break;
+ case 1:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint64_t*)0x200001d0 = 0x20000180;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint64_t*)0x20000188 = 0x3d2;
+ *(uint64_t*)0x200001d8 = 1;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001f0 = 0;
+ syscall(__NR_sendmsg, r[1], 0x200001c0ul, 0ul);
+ break;
+ case 4:
+ *(uint32_t*)0x20000280 = 0x19d;
+ res = syscall(__NR_getsockname, r[1], 0x20000080ul, 0x20000280ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000084;
+ break;
+ case 5:
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ break;
+ case 6:
+ res = syscall(__NR_socket, 0x200000000000011ul, 3ul, 0);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 7:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 8:
+ memcpy((void*)0x200003c0, "netdevsim0\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x200003d0 = 0;
+ res = syscall(__NR_ioctl, r[4], 0x8933ul, 0x200003c0ul);
+ if (res != -1)
+ r[5] = *(uint32_t*)0x200003d0;
+ break;
+ case 9:
+ *(uint16_t*)0x20000240 = 0x11;
+ *(uint16_t*)0x20000242 = htobe16(0);
+ *(uint32_t*)0x20000244 = r[5];
+ *(uint16_t*)0x20000248 = 1;
+ *(uint8_t*)0x2000024a = 0;
+ *(uint8_t*)0x2000024b = 6;
+ *(uint8_t*)0x2000024c = 0;
+ *(uint8_t*)0x2000024d = 0;
+ *(uint8_t*)0x2000024e = 0;
+ *(uint8_t*)0x2000024f = 0;
+ *(uint8_t*)0x20000250 = 0;
+ *(uint8_t*)0x20000251 = 0;
+ *(uint8_t*)0x20000252 = 0;
+ *(uint8_t*)0x20000253 = 0;
+ syscall(__NR_bind, r[3], 0x20000240ul, 0x14ul);
+ break;
+ case 10:
+ *(uint32_t*)0x20000040 = 0x10eef0f1;
+ res = syscall(__NR_getsockname, r[3], 0x20000500ul, 0x20000040ul);
+ if (res != -1)
+ r[6] = *(uint32_t*)0x20000504;
+ break;
+ case 11:
+ *(uint64_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint64_t*)0x20000010 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20002700;
+ *(uint32_t*)0x20002700 = 0x28;
+ *(uint16_t*)0x20002704 = 0x10;
+ *(uint16_t*)0x20002706 = 0x401;
+ *(uint32_t*)0x20002708 = 0;
+ *(uint32_t*)0x2000270c = 0;
+ *(uint8_t*)0x20002710 = 0;
+ *(uint8_t*)0x20002711 = 0;
+ *(uint16_t*)0x20002712 = 0;
+ *(uint32_t*)0x20002714 = r[6];
+ *(uint32_t*)0x20002718 = 0;
+ *(uint32_t*)0x2000271c = 0;
+ *(uint16_t*)0x20002720 = 8;
+ *(uint16_t*)0x20002722 = 0xa;
+ *(uint32_t*)0x20002724 = r[2];
+ *(uint64_t*)0x200000c8 = 0x28;
+ *(uint64_t*)0x20000018 = 1;
+ *(uint64_t*)0x20000020 = 0;
+ *(uint64_t*)0x20000028 = 0;
+ *(uint32_t*)0x20000030 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000000ul, 0ul);
+ break;
+ case 12:
+ res = syscall(__NR_socket, 0x11ul, 2ul, 0x300ul);
+ if (res != -1)
+ r[7] = res;
+ break;
+ case 13:
+ res = syscall(__NR_socket, 0x200000000000011ul, 3ul, 0);
+ if (res != -1)
+ r[8] = res;
+ break;
+ case 14:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[9] = res;
+ break;
+ case 15:
+ memcpy((void*)0x200003c0, "netdevsim0\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x200003d0 = 0;
+ res = syscall(__NR_ioctl, r[9], 0x8933ul, 0x200003c0ul);
+ if (res != -1)
+ r[10] = *(uint32_t*)0x200003d0;
+ break;
+ case 16:
+ *(uint16_t*)0x20000240 = 0x11;
+ *(uint16_t*)0x20000242 = htobe16(0);
+ *(uint32_t*)0x20000244 = r[10];
+ *(uint16_t*)0x20000248 = 1;
+ *(uint8_t*)0x2000024a = 0;
+ *(uint8_t*)0x2000024b = 6;
+ *(uint8_t*)0x2000024c = 0;
+ *(uint8_t*)0x2000024d = 0;
+ *(uint8_t*)0x2000024e = 0;
+ *(uint8_t*)0x2000024f = 0;
+ *(uint8_t*)0x20000250 = 0;
+ *(uint8_t*)0x20000251 = 0;
+ *(uint8_t*)0x20000252 = 0;
+ *(uint8_t*)0x20000253 = 0;
+ syscall(__NR_bind, r[8], 0x20000240ul, 0x14ul);
+ break;
+ case 17:
+ *(uint32_t*)0x20000040 = 0x10eef0f1;
+ res = syscall(__NR_getsockname, r[8], 0x20000500ul, 0x20000040ul);
+ if (res != -1)
+ r[11] = *(uint32_t*)0x20000504;
+ break;
+ case 18:
+ *(uint16_t*)0x20000100 = 0x11;
+ *(uint16_t*)0x20000102 = htobe16(0xf6);
+ *(uint32_t*)0x20000104 = r[11];
+ *(uint16_t*)0x20000108 = 1;
+ *(uint8_t*)0x2000010a = 0x20;
+ *(uint8_t*)0x2000010b = 6;
+ *(uint8_t*)0x2000010c = 0xaa;
+ *(uint8_t*)0x2000010d = 0xaa;
+ *(uint8_t*)0x2000010e = 0xaa;
+ *(uint8_t*)0x2000010f = 0xaa;
+ *(uint8_t*)0x20000110 = 0xaa;
+ *(uint8_t*)0x20000111 = 0x10;
+ *(uint8_t*)0x20000112 = 0;
+ *(uint8_t*)0x20000113 = 0;
+ syscall(__NR_sendto, r[7], 0x200002c0ul, 0ul, 0x4020083ul, 0x20000100ul,
+ 0x14ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/98b14adec5e7c3a28f76e2ac90de27b064bfd9d6.c b/syzkaller-repros/linux/98b14adec5e7c3a28f76e2ac90de27b064bfd9d6.c
new file mode 100644
index 0000000..5d7aa29
--- /dev/null
+++ b/syzkaller-repros/linux/98b14adec5e7c3a28f76e2ac90de27b064bfd9d6.c
@@ -0,0 +1,1467 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ exit(1);
+ }
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1) {
+ return;
+ }
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_accept4, -1, 0ul, 0ul, 0x800ul);
+ break;
+ case 1:
+ syscall(__NR_semctl, 0, 0ul, 0xdul, 0ul);
+ break;
+ case 2:
+ memcpy((void*)0x20000000, "/dev/fd#\000", 9);
+ res = syz_open_dev(0x20000000, 0, 0x802);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 3:
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0xafc;
+ *(uint32_t*)0x20000048 = 7;
+ *(uint32_t*)0x2000004c = 1;
+ *(uint32_t*)0x20000050 = 2;
+ *(uint8_t*)0x20000054 = 0;
+ *(uint8_t*)0x20000055 = 0x3f;
+ *(uint8_t*)0x20000056 = 0;
+ *(uint8_t*)0x20000057 = 0;
+ *(uint64_t*)0x20000058 = 0;
+ syscall(__NR_ioctl, r[0], 0x40200242ul, 0x20000040ul);
+ break;
+ case 4:
+ syscall(__NR_semctl, 0, 0ul, 0xdul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 6; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/997f131c54f3af896f51a273b479033ac59eca54.c b/syzkaller-repros/linux/997f131c54f3af896f51a273b479033ac59eca54.c
new file mode 100644
index 0000000..dfbd829
--- /dev/null
+++ b/syzkaller-repros/linux/997f131c54f3af896f51a273b479033ac59eca54.c
@@ -0,0 +1,219 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x74;
+ *(uint8_t*)0x20000004 = 2;
+ *(uint8_t*)0x20000005 = 6;
+ *(uint16_t*)0x20000006 = 1;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 0;
+ *(uint16_t*)0x20000012 = htobe16(0);
+ *(uint16_t*)0x20000014 = 0xe;
+ *(uint16_t*)0x20000016 = 3;
+ memcpy((void*)0x20000018, "bitmap:ip\000", 10);
+ *(uint16_t*)0x20000024 = 9;
+ *(uint16_t*)0x20000026 = 2;
+ memcpy((void*)0x20000028, "syz1\000", 5);
+ *(uint16_t*)0x20000030 = 0x2c;
+ STORE_BY_BITMASK(uint16_t, , 0x20000032, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000033, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000033, 1, 7, 1);
+ *(uint16_t*)0x20000034 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000036, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000037, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000037, 1, 7, 1);
+ *(uint16_t*)0x20000038 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000003a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000003b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000003b, 0, 7, 1);
+ *(uint32_t*)0x2000003c = htobe32(0);
+ *(uint16_t*)0x20000040 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000042, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000043, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000043, 1, 7, 1);
+ *(uint16_t*)0x20000044 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000046, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000047, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000047, 0, 7, 1);
+ *(uint8_t*)0x20000048 = 0xac;
+ *(uint8_t*)0x20000049 = 0x1e;
+ *(uint8_t*)0x2000004a = 0;
+ *(uint8_t*)0x2000004b = 1;
+ *(uint16_t*)0x2000004c = 5;
+ *(uint16_t*)0x2000004e = 0x14;
+ *(uint8_t*)0x20000050 = 1;
+ *(uint16_t*)0x20000054 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000056, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000057, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000057, 0, 7, 1);
+ *(uint32_t*)0x20000058 = htobe32(0);
+ *(uint16_t*)0x2000005c = 5;
+ *(uint16_t*)0x2000005e = 1;
+ *(uint8_t*)0x20000060 = 7;
+ *(uint16_t*)0x20000064 = 5;
+ *(uint16_t*)0x20000066 = 4;
+ *(uint8_t*)0x20000068 = 0;
+ *(uint16_t*)0x2000006c = 5;
+ *(uint16_t*)0x2000006e = 5;
+ *(uint8_t*)0x20000070 = 2;
+ *(uint64_t*)0x200002c8 = 0x74;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/99fed9c49f1dcedc898556e2bfc2214578fbfc4f.c b/syzkaller-repros/linux/99fed9c49f1dcedc898556e2bfc2214578fbfc4f.c
new file mode 100644
index 0000000..cbad766
--- /dev/null
+++ b/syzkaller-repros/linux/99fed9c49f1dcedc898556e2bfc2214578fbfc4f.c
@@ -0,0 +1,79 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x200031c0 = 0;
+ *(uint32_t*)0x200031c8 = 0;
+ *(uint64_t*)0x200031d0 = 0x20003180;
+ *(uint64_t*)0x20003180 = 0x20003000;
+ *(uint32_t*)0x20003000 = 0x38;
+ *(uint16_t*)0x20003004 = 0x1403;
+ *(uint16_t*)0x20003006 = 1;
+ *(uint32_t*)0x20003008 = 0;
+ *(uint32_t*)0x2000300c = 0;
+ *(uint16_t*)0x20003010 = 9;
+ *(uint16_t*)0x20003012 = 2;
+ memcpy((void*)0x20003014, "syz1\000", 5);
+ *(uint16_t*)0x2000301c = 8;
+ *(uint16_t*)0x2000301e = 0x41;
+ memcpy((void*)0x20003020, "siw\000", 4);
+ *(uint16_t*)0x20003024 = 0x14;
+ *(uint16_t*)0x20003026 = 0x33;
+ memcpy((void*)0x20003028,
+ "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint64_t*)0x20003188 = 0x38;
+ *(uint64_t*)0x200031d8 = 1;
+ *(uint64_t*)0x200031e0 = 0;
+ *(uint64_t*)0x200031e8 = 0;
+ *(uint32_t*)0x200031f0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x200031c0ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint64_t*)0x20000250 = 0x20000200;
+ *(uint64_t*)0x20000200 = 0x20000180;
+ *(uint32_t*)0x20000180 = 0x30;
+ *(uint16_t*)0x20000184 = 0x1410;
+ *(uint16_t*)0x20000186 = 1;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint32_t*)0x2000018c = 0;
+ *(uint16_t*)0x20000190 = 8;
+ *(uint16_t*)0x20000192 = 0x4b;
+ *(uint32_t*)0x20000194 = 0x13;
+ *(uint16_t*)0x20000198 = 8;
+ *(uint16_t*)0x2000019a = 0x4a;
+ *(uint32_t*)0x2000019c = 0;
+ *(uint16_t*)0x200001a0 = 8;
+ *(uint16_t*)0x200001a2 = 1;
+ *(uint32_t*)0x200001a4 = 0;
+ *(uint16_t*)0x200001a8 = 8;
+ *(uint16_t*)0x200001aa = 3;
+ *(uint32_t*)0x200001ac = 1;
+ *(uint64_t*)0x20000208 = 0x30;
+ *(uint64_t*)0x20000258 = 1;
+ *(uint64_t*)0x20000260 = 0;
+ *(uint64_t*)0x20000268 = 0;
+ *(uint32_t*)0x20000270 = 0x20000021;
+ syscall(__NR_sendmsg, r[1], 0x20000240ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/9ca49645a6602cde90a9f62497d1b4f1a3dfdc31.c b/syzkaller-repros/linux/9ca49645a6602cde90a9f62497d1b4f1a3dfdc31.c
new file mode 100644
index 0000000..4a49f0f
--- /dev/null
+++ b/syzkaller-repros/linux/9ca49645a6602cde90a9f62497d1b4f1a3dfdc31.c
@@ -0,0 +1,244 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+void execute_one(void)
+{
+ syscall(__NR_perf_event_open, 0, 0, 0, -1, 0);
+ memcpy((void*)0x20000000, "/dev/cuse\000", 10);
+ inject_fault(10);
+ syscall(__NR_openat, 0xffffffffffffff9c, 0x20000000, 2, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/9ccfdd8b47bdb95ad17277f7c1b055c4dcef1bfe.c b/syzkaller-repros/linux/9ccfdd8b47bdb95ad17277f7c1b055c4dcef1bfe.c
new file mode 100644
index 0000000..447c6a8
--- /dev/null
+++ b/syzkaller-repros/linux/9ccfdd8b47bdb95ad17277f7c1b055c4dcef1bfe.c
@@ -0,0 +1,50 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20003e00 = 0;
+ *(uint32_t*)0x20003e08 = 0;
+ *(uint64_t*)0x20003e10 = 0x20003dc0;
+ *(uint64_t*)0x20003dc0 = 0x20000340;
+ memcpy(
+ (void*)0x20000340,
+ "\x14\x00\x00\x00\x10\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x0a\x20\x00\x00\x00\x00\x0a\x05\x14\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x01\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x6c\x00"
+ "\x00\x00\x16\x0a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
+ "\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x09\x00\x02\x00\x73\x79"
+ "\x7a\x32\x00\x00\x00\x00\x40\x00\x03\x80\x2c\x00\x03\x80\x14\x00\x01\x00"
+ "\x6c\x6f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x14\x00"
+ "\x01\x00\x73\x69\x74\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x08\x00\x02\x40\x00\x00\x00\x00\x08\x00\x01\x40\x00\x00\x00\x00\x20\x00"
+ "\x00\x00\x12\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09"
+ "\x00\x02\x00\x73\x79\x7a\x31\x00\x00\x00\x00\x00\x11\x00\x01\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\xba\x56\xc0\x87\x03\x24\x64\x34"
+ "\x4c\x01\x3c\x00\x00\x00\x00",
+ 223);
+ *(uint64_t*)0x20003dc8 = 0xd4;
+ *(uint64_t*)0x20003e18 = 1;
+ *(uint64_t*)0x20003e20 = 0;
+ *(uint64_t*)0x20003e28 = 0;
+ *(uint32_t*)0x20003e30 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20003e00ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/9dfe96b48c8570c16eb2f2c874b494731d5de11a.c b/syzkaller-repros/linux/9dfe96b48c8570c16eb2f2c874b494731d5de11a.c
new file mode 100644
index 0000000..1fad756
--- /dev/null
+++ b/syzkaller-repros/linux/9dfe96b48c8570c16eb2f2c874b494731d5de11a.c
@@ -0,0 +1,372 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0x20;
+ *(uint32_t*)0x2000004c = 0x13;
+ *(uint32_t*)0x20000050 = 0x100;
+ *(uint64_t*)0x20000058 = 0x200003c0;
+ memcpy(
+ (void*)0x200003c0,
+ "\xcb\xb6\x2c\x7c\x7e\x12\x72\x7d\x60\xc5\xdb\x26\x5c\x1d\x8b\x3f\x75\x25"
+ "\x50\xd4\xea\xc7\xaf\xf1\x02\x13\x26\xe1\x5d\xfd\xad\x91\x1d\x57\xa8\x53"
+ "\x41\x4b\x19\x47\x02\xa4\x1a\x75\x60\x56\x8b\xe1\x11\x1d\xac\x9f\xf2\x58"
+ "\x6d\x67\xdc\x8e\xf3\xe9\xd3\x66\x94\xc5\xea\x96\xd8\x98\x5a\x99\x53\xe8"
+ "\x77\x5c\xbf\x7a\xe1\x51\xea\x1f\xd6\x08\x63\xac\xd9\xe7\x60\x31\x83\x3d"
+ "\xff\xb4\x47\xc4\x25\xc9\x74\x9c\x7d\xe7\xfb\xe2\xe5\x65\xb4\xa2\x5f\x7b"
+ "\x2a\xc0\x13\x92\xce\x04\xec\x8d\x6d\x21\x0e\x0a\x23\xae\x3a\x5f\xd8\x1c"
+ "\x3c\x89\xc9\x28\x74\x70\x9f\xcd\xd4\xd4\xc3\xff\xe7\xfa\x05\x2a\xc6\x8f"
+ "\xb6\x01\x7e\x48\x2e\x24\xbe\x6a\xc8\x19\x10\x39\xb4\x34\xaa\x0e\x9f\x97"
+ "\x39\xae\xdf\x30\xc0\xfa\x9c\x42\xcd\xa4\x11\x02\x5c\xa2\x0c\x42\xbf\x88"
+ "\x68\x56\x03\x99\x87\x3f\x4d\x1b\x28\xed\x71\x3e\x41\x1b\x34\xec\x02\x63"
+ "\x21\xc8\xcd\x9a\xd1\x7c\xbc\x95\x70\x4c\x14\x2d\x7c\x71\x06\x3b\x4a\x0b"
+ "\x52\xe2\x20\x73\xf8\x59\xd6\x32\x89\x92\x12\x6e\x5f\x50\x57\xad\x1d\x02"
+ "\x29\xba\xde\xc1\xe0\x88\x0f\x47\x6f\x18\xce\x68\x55\x60\x78\xa0\x06\x7d"
+ "\x8e\x90\x05\x7f\x56\x0b\x51\x51\xc4\x50\xe6\x55\x89\x81\x2f\x77\x9b\x50"
+ "\xe4\xde\xd6\x60\xee\x4a\xa6\x1e\x7f\x84\xa9\xb4\xb7\x91\x83\x71\x14\x09"
+ "\x55\x39\xfb\x55\x73\xe4\x7c\xce\x26\xdc\x38\x31\x19\x13\x99\x51\x81\xe7"
+ "\x28\xfd\x4d\x6d\x33\x4e\x62\xfd\x0a\x82\x2f\x93\x71\xbc\xdc\x43\xc8\xa6"
+ "\x96\x88\xa1\x1f\xc9\xf4\x3a\xfe\x64\x2c\x30\xdd\xf3\x94\x65\xb1\x3c\xf1"
+ "\xdd\xad\xd7\x89\x70\x77\x18\x27\xf4\x45\xf0\xd4\x56\x1e\x8e\x2b\xb6\xcf"
+ "\x22\x44\x63\x4b\xcd\x72\xd1\x24\xf3\xca\xa1\x52\xc6\xfd\x6d\x47\xbb\x00"
+ "\x4b\x97\x97\x5d\x4a\x46\xb2\xee\x12\x9b\x88\x9d\xc5\x9c\x1c\x71\x62\xff"
+ "\xf2\x2c\x42\x95\x54\x52\x95\xea\x72\xfe\x14\xc6\xb2\xba\xb3\x5a\xb5\x45"
+ "\x51\x73\x98\xb0\x03\xb6\xd3\xb8\x9c\x5c\x64\xb4\x49\xf7\xd5\x60\xdd\xe2"
+ "\x0f\xc1\x3b\x3e\xc8\x8d\xc0\x52\x42\xa1\x60\x07\x6c\xcb\xff\x3e\x32\xb8"
+ "\x78\x0b\xd1\x91\xa0\xb1\x2a\x6f\x99\x00\xa9\x37\xa1\x2d\x9f\xb5\xed\x34"
+ "\x88\xd5\xcd\x0a\xa3\x29\x58\x3f\x2c\x47\xc4\xfd\x47\x26\x46\x9c\x98\xe0"
+ "\xb6\x6d\x74\xc3\x1d\x0a\x1f\x7f\xc1\x0c\xc1\x94\x4d\x25\x26\x7e\xff\x7a"
+ "\x74\x0c\xc4\x13\x06\x9b\x58\x47\x9c\xa6\x96\x00\x63\x6a\x0f\x22\xa4\x70"
+ "\xa6\x9b\x46\xc1\xcc\x1b\x95\xcf\x32\xdd\x7b\x73\xad\x67\x41\x61\xca\x39"
+ "\x25\x83\xaa\x83\x4a\xaa\xde\x88\xa4\x39\x33\x89\xb7\x6d\x58\x8a\x60\x81"
+ "\x91\xdb\x7c\xa7\x5d\xd0\x09\x38\x2a\x45\x83\xe8\x78\x1e\xb0\x9f\x48\xa4"
+ "\x4d\x06\xb4\x17\x56\xeb\x3f\x1b\x7e\xea\x18\xad\xf2\x97\x83\x22\xd0\xb3"
+ "\x84\xdf\x03\x07\x98\x91\xe1\x0f\x09\x2c\x57\x33\x20\xfb\x94\x1f\x10\xe3"
+ "\xc3\xaf\x6f\x3e\x72\xb2\xaf\xcd\x95\xa3\x66\x6a\x6a\x40\xa8\x40\xe6\x3d"
+ "\x1c\xb9\xe2\x49\x25\xc0\x49\x7a\x04\xef\x7b\x9b\x1e\xe3\x9d\xe0\x45\x6f"
+ "\xec\xd6\x76\xac\xee\x23\x3f\x5b\x64\x5e\x8d\x05\xf3\xf5\x05\xa1\x2a\x0f"
+ "\x5b\x35\x65\x86\xf2\x2c\x2c\x2c\xeb\xef\x83\xc5\xe6\x8c\x22\x72\x34\x95"
+ "\xab\xa0\x64\x27\x92\x55\xde\x48\x9e\x33\xe9\x20\x9a\x63\x68\x90\xbc\xfb"
+ "\x2a\x52\x7e\x8d\xa8\x36\x21\xae\xf3\x74\xf5\xa1\x1d\x8a\xc7\x7f\x5d\xcd"
+ "\x42\x1f\x45\xe5\x2d\xdf\x9b\xc3\x5f\x64\xcf\x72\x1c\xe6\xc9\x6b\x56\x13"
+ "\x26\x8c\x02\x5c\xa9\x91\x0a\x8a\x23\x5e\x6a\xf3\xd6\x7a\xdd\xc6\x6e\x75"
+ "\xc1\x56\x4a\x7f\x86\x84\xfc\xd2\x3e\xc9\x8d\x61\xa4\xfa\x42\x2c\x55\xe6"
+ "\x78\x9c\xbc\x42\xb1\xd5\x32\x63\x3e\x65\x8a\x5c\x2f\xfe\x57\x67\x03\x97"
+ "\x62\xf1\x8c\xce\x89\xb8\x00\x0e\x37\xca\xbc\x35\x40\x9d\x3c\x7a\x02\x13"
+ "\xde\x87\xce\x95\xcf\xbf\xb0\xc7\x1b\xe4\xc4\xef\x44\x86\x6b\xd8\xe0\x50"
+ "\xe3\x36\xb3\x1a\x6e\x8f\x15\xbd\x21\x60\xef\x48\x48\xad\xa2\x56\xdf\x90"
+ "\x27\x58\xeb\xbc\x1e\x83\x7f\xab\x4c\xb8\xbb\x84\x67\xa7\x3d\xf7\x17\xd9"
+ "\x2e\x22\x04\x48\x2f\xe9\x5c\x21\x12\x11\x86\xa5\x7c\x3b\x12\xf7\x5c\x83"
+ "\x6a\xb7\x02\x43\x34\x18\xf3\x29\x44\x32\x3e\xaa\xad\xbc\xa3\x66\x96\x1c"
+ "\x25\x62\x0c\x43\x95\x1a\x7a\x3f\xd3\xe3\xcc\x85\xd6\xa3\x99\x6b\x50\xd1"
+ "\x2e\xa7\x6d\xf6\x58\xa6\x40\x5f\xdf\x1c\x9f\x2c\x05\x24\x8d\x95\x15\xce"
+ "\x96\x65\x0e\xbf\x62\x96\x64\xe6\xc1\x92\xdd\x28\xe1\x61\x72\xbe\x15\x93"
+ "\xe9\x4d\xbc\xa0\xe5\x54\xfc\xe9\x73\x6c\x73\x54\x03\x0c\x64\xfd\xaf\x35"
+ "\x03\x8e\x1f\x1e\x1d\x20\xe0\x6f\x34\x8e\xf5\xae\x75\x41\x39\xb4\xe8\x12"
+ "\xc6\x0f\xbc\x55\xba\xce\x83\xf2\x7b\xb8\x35\xc1\x64\xc2\x9f\x5f\x7c\x1d"
+ "\xbe\xeb\xfd\x98\x8a\x16\x23\x5c\x4b\xbe\xe4\xd9\xa3\xbc\x66\x6f",
+ 1024);
+ syscall(__NR_ioctl, r[0], 0x4b72ul, 0x20000040ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ *(uint32_t*)0x20000000 = 3;
+ *(uint32_t*)0x20000004 = 1;
+ *(uint32_t*)0x20000008 = 0xfffffffe;
+ *(uint32_t*)0x2000000c = 5;
+ *(uint32_t*)0x20000010 = 0x40193;
+ *(uint64_t*)0x20000018 = 0;
+ syscall(__NR_ioctl, r[1], 0x4b72ul, 0x20000000ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/9f4072db0f477dd9e755f50a2186a4c8cd377c64.c b/syzkaller-repros/linux/9f4072db0f477dd9e755f50a2186a4c8cd377c64.c
new file mode 100644
index 0000000..39984f3
--- /dev/null
+++ b/syzkaller-repros/linux/9f4072db0f477dd9e755f50a2186a4c8cd377c64.c
@@ -0,0 +1,238 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000040, "/dev/sg#\000", 9);
+ res = syz_open_dev(0x20000040, 1, 0x163886);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000000,
+ "\x00\x00\x00\x00\xd5\x01\x04\x00\x00\x00\x00\x01\x00\x00\xce\xcc\xf9"
+ "\xd7\x23\x64\x4b\xed\xba\x3d\xda\xd8\x5b\x85\xfd\x00\x00\xba\xa5\xb5"
+ "\xe8\xd2\x53\xf0\x06\x65\xe3\xe8\x97\x76\xf8\xe5\x3d\x3a\xc7\x80\xdb"
+ "\x07\x00\x00\x00",
+ 55);
+ syscall(__NR_write, r[0], 0x20000000, 0x37);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/9f97c7066f70c61e5d9d42da3ccd5917ec81c8b2.c b/syzkaller-repros/linux/9f97c7066f70c61e5d9d42da3ccd5917ec81c8b2.c
new file mode 100644
index 0000000..342149d
--- /dev/null
+++ b/syzkaller-repros/linux/9f97c7066f70c61e5d9d42da3ccd5917ec81c8b2.c
@@ -0,0 +1,269 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <errno.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+__attribute__((noreturn)) static void doexit(int status)
+{
+ volatile unsigned i;
+ syscall(__NR_exit_group, status);
+ for (i = 0;; i++) {
+ }
+}
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+const int kFailStatus = 67;
+const int kRetryStatus = 69;
+
+static void fail(const char* msg, ...)
+{
+ int e = errno;
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, " (errno %d)\n", e);
+ doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
+}
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* uctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ doexit(sig);
+}
+
+static void install_segv_handler()
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = 160 << 20;
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 8 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid < 0)
+ fail("sandbox fork failed");
+ if (pid)
+ return pid;
+
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ doexit(1);
+}
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[5] = {0x0, 0x0, 0x0, 0x0, 0x0};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_semget, 0, 4, 2);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ NONFAILING(*(uint32_t*)0x20000100 = 0xe8);
+ res = syscall(__NR_getsockopt, 0xffffff9c, 0x29, 0x22, 0x20000000,
+ 0x20000100);
+ if (res != -1)
+ NONFAILING(r[1] = *(uint32_t*)0x20000034);
+ break;
+ case 2:
+ res = syscall(__NR_fstat, 0xffffff9c, 0x20000140);
+ if (res != -1)
+ NONFAILING(r[2] = *(uint32_t*)0x20000150);
+ break;
+ case 3:
+ NONFAILING(*(uint32_t*)0x20000200 = 0xc);
+ res = syscall(__NR_getsockopt, 0xffffff9c, 1, 0x11, 0x200001c0, 0x20000200);
+ if (res != -1)
+ NONFAILING(r[3] = *(uint32_t*)0x200001c4);
+ break;
+ case 4:
+ res = syscall(__NR_getgid);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 5:
+ NONFAILING(*(uint32_t*)0x20000240 = 0x1f);
+ NONFAILING(*(uint32_t*)0x20000244 = r[1]);
+ NONFAILING(*(uint32_t*)0x20000248 = r[2]);
+ NONFAILING(*(uint32_t*)0x2000024c = r[3]);
+ NONFAILING(*(uint32_t*)0x20000250 = r[4]);
+ NONFAILING(*(uint32_t*)0x20000254 = 9);
+ NONFAILING(*(uint16_t*)0x20000258 = 1);
+ NONFAILING(*(uint16_t*)0x2000025a = 0);
+ NONFAILING(*(uint64_t*)0x20000260 = 0);
+ NONFAILING(*(uint64_t*)0x20000268 = 0);
+ NONFAILING(*(uint64_t*)0x20000270 = 6);
+ NONFAILING(*(uint64_t*)0x20000278 = 0);
+ NONFAILING(*(uint64_t*)0x20000280 = 0x100000001);
+ NONFAILING(*(uint64_t*)0x20000288 = 0);
+ NONFAILING(*(uint64_t*)0x20000290 = 0);
+ syscall(__NR_semctl, r[0], 0, 1, 0x20000240);
+ break;
+ case 6:
+ syscall(__NR_semctl, r[0], 0, 0);
+ break;
+ }
+}
+
+void loop()
+{
+ execute(7);
+ collide = 1;
+ execute(7);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ install_segv_handler();
+ int pid = do_sandbox_none();
+ int status = 0;
+ while (waitpid(pid, &status, __WALL) != pid) {
+ }
+ return 0;
+}
diff --git a/syzkaller-repros/linux/9fd843999c6e320661905cafc1eb3e9b36691e63.c b/syzkaller-repros/linux/9fd843999c6e320661905cafc1eb3e9b36691e63.c
new file mode 100644
index 0000000..c83c7da
--- /dev/null
+++ b/syzkaller-repros/linux/9fd843999c6e320661905cafc1eb3e9b36691e63.c
@@ -0,0 +1,207 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000280 = 0;
+ *(uint32_t*)0x20000288 = 8;
+ *(uint64_t*)0x20000290 = 0x20000240;
+ *(uint64_t*)0x20000240 = 0x20000100;
+ memcpy((void*)0x20000100,
+ "\x14\x00\x00\x00\x10\x00\x00\x00\x1e\x6c\x00\x00\x00\x08\x00\x00\x00"
+ "\x00\x00\x0a\x20\x00\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00"
+ "\x00\x38\x00\x00\x00\x12\x0a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x04\x00\x04\x80\x09\x00\x02\x00\x00\x39\x7d\x00\x00"
+ "\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00"
+ "\x03\x40\x00\x00\x00\x01\x14\x00\x00\x00\x11\x00\xdf\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x0a",
+ 128);
+ *(uint64_t*)0x20000248 = 0x80;
+ *(uint64_t*)0x20000298 = 1;
+ *(uint64_t*)0x200002a0 = 0;
+ *(uint64_t*)0x200002a8 = 0;
+ *(uint32_t*)0x200002b0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000280ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20009bc0 = 0;
+ *(uint32_t*)0x20009bc8 = 0;
+ *(uint64_t*)0x20009bd0 = 0x20009b80;
+ *(uint64_t*)0x20009b80 = 0x20003b00;
+ *(uint32_t*)0x20003b00 = 0x14;
+ *(uint16_t*)0x20003b04 = 0x10;
+ *(uint16_t*)0x20003b06 = 1;
+ *(uint32_t*)0x20003b08 = 0;
+ *(uint32_t*)0x20003b0c = 0;
+ *(uint8_t*)0x20003b10 = 0;
+ *(uint8_t*)0x20003b11 = 0;
+ *(uint16_t*)0x20003b12 = htobe16(0xa);
+ *(uint32_t*)0x20003b14 = 0x3c;
+ *(uint8_t*)0x20003b18 = 3;
+ *(uint8_t*)0x20003b19 = 0xa;
+ *(uint16_t*)0x20003b1a = 0x401;
+ *(uint32_t*)0x20003b1c = 0;
+ *(uint32_t*)0x20003b20 = 0;
+ *(uint8_t*)0x20003b24 = 0;
+ *(uint8_t*)0x20003b25 = 0;
+ *(uint16_t*)0x20003b26 = htobe16(0);
+ *(uint16_t*)0x20003b28 = 8;
+ *(uint16_t*)0x20003b2a = 7;
+ memcpy((void*)0x20003b2c, "nat\000", 4);
+ *(uint16_t*)0x20003b30 = 9;
+ *(uint16_t*)0x20003b32 = 1;
+ memcpy((void*)0x20003b34, "syz0\000", 5);
+ *(uint16_t*)0x20003b3c = 4;
+ STORE_BY_BITMASK(uint16_t, , 0x20003b3e, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003b3f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003b3f, 1, 7, 1);
+ *(uint16_t*)0x20003b40 = 9;
+ *(uint16_t*)0x20003b42 = 3;
+ memcpy((void*)0x20003b44, "syz0\000", 5);
+ *(uint16_t*)0x20003b4c = 4;
+ STORE_BY_BITMASK(uint16_t, , 0x20003b4e, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20003b4f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20003b4f, 1, 7, 1);
+ *(uint32_t*)0x20003b50 = 0x14;
+ *(uint16_t*)0x20003b54 = 0x11;
+ *(uint16_t*)0x20003b56 = 1;
+ *(uint32_t*)0x20003b58 = 0;
+ *(uint32_t*)0x20003b5c = 0;
+ *(uint8_t*)0x20003b60 = 0;
+ *(uint8_t*)0x20003b61 = 0;
+ *(uint16_t*)0x20003b62 = htobe16(0xa);
+ *(uint64_t*)0x20009b88 = 0x64;
+ *(uint64_t*)0x20009bd8 = 1;
+ *(uint64_t*)0x20009be0 = 0;
+ *(uint64_t*)0x20009be8 = 0;
+ *(uint32_t*)0x20009bf0 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20009bc0ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[2] = res;
+ *(uint64_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint64_t*)0x20000250 = 0x20000200;
+ *(uint64_t*)0x20000200 = 0x20000280;
+ memcpy(
+ (void*)0x20000280,
+ "\x14\x00\x00\x00\x10\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x0a\x18\x05\x00\x00\x06\x0a\x01\x04\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x09\x00\x02\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x09\x00"
+ "\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\xec\x04\x04\x80\xe8\x04\x01\x80"
+ "\x92\x00\x01\x00\x63\x6d\x70\x00\xdc\x04\x02\x80\xd8\x04\x03\x80\x11\x00"
+ "\x01\x00\xa0\x3b\xee\xc5\xab\x1e\xaf\xc6\x76\x42\x24\xe3\xf1\x00\x00\x00"
+ "\x40\x00\x01\x00\xd4\x74\x9c\x14\x6f\xe5\x6c\xe1\x20\xed\x01\x25\x8e\x7a"
+ "\x3d\xbe\x6e\x8a\x56\xfc\x6b\x33\xf4\xb7\x92\x86\xe9\x35\x07\xa2\x41\x16"
+ "\x9f\xa3\xc9\xd3\xb9\xc9\x88\x54\x8b\x4f\x3b\xd3\xbd\xce\x6b\x70\xb9\x6c"
+ "\x2a\x8a\x22\x9c\x02\x83\xf3\x9a\x78\x0d\x6c\x00\x02\x80\x09\x00\x02\x00"
+ "\x73\x79\x7a\x32\x00\x00\x00\x00\x09\x00\x02\x00\x73\x79\x7a\x31\x00\x00"
+ "\x00\x00\x09\x00\x02\x00\x73\x79\x7a\x31\x00\x00\x00\x00\x08\x00\x01\x80"
+ "\xff\xff\xff\xff\x08\x00\x01\x80\xff\xff\xff\xf6\x09\x00\x02\x00\x73\x79"
+ "\x7a\x32\x00\x00\x00\x00\x09\x00\x02\x00\x73\x79\x7a\x31\x00\x00\x00\x00"
+ "\x08\x00\x01\x80\xff\xff\xff\xfd\x09\x00\x02\x00\x73\x79\x7a\x30\x00\x00"
+ "\x00\x00\x08\x00\x01\x80\xff\xff\xff\xfd\x50\x00\x02\x80\x08\x00\x01\x80"
+ "\xff\xff\xff\xfe\x08\x00\x01\x80\xff\xff\xff\xfc\x08\x00\x01\x80\xff\xff"
+ "\xff\xfe\x09\x00\x02\x00\x73\x79\x7a\x32\x00\x00\x00\x00\x08\x00\x01\x80"
+ "\xff\xff\xff\xfc\x08\x00\x01\x80\xff\xff\xff\xfc\x08\x00\x01\x80\xff\xff"
+ "\xff\xfb\x08\x00\x01\x80\xff\xff\xff\xff\x08\x00\x01\x80\xff\xff\xff\xfd"
+ "\xca\x00\x01\x00\x9d\xfc\xd6\x4c\x4d\x4d\x52\xf6\x7e\xab\x1e\xff\x2a\x9f"
+ "\x7b\x7f\xac\x8f\xfc\x46\xfe\x9e\x17\x83\xb5\x0b\x0b\x44\x63\xe2\x06\xba"
+ "\x48\x8f\x63\x16\x28\x16\x9b\xdd\x3f\x56\x1c\xaa\x38\xdc\x3f\xb6\x28\x74"
+ "\x18\x28\x73\x4b\x8a\x6c\x3a\x17\xdc\xae\xfd\x0d\x4c\x56\xd7\x9f\x4d\xcb"
+ "\x1d\xd1\x6f\x03\x86\x3d\xf5\x96\x0c\xb2\x0c\x86\x3d\xdc\xa7\x10\x6e\xc0"
+ "\xed\xfa\xc2\xc2\xe5\xd7\x5a\x49\xe6\x74\x7a\xf1\x82\xe1\x0a\x09\x18\xde"
+ "\x6a\x6b\x16\x1d\xb8\xb9\xf7\xb0\xe4\x03\x37\x51\x9b\x11\x6a\xcd\x8a\xbb"
+ "\x12\x0e\x70\x95\x30\x1f\xf6\x9e\x9a\xd4\x12\xf3\x9b\x2d\xa3\x0b\xf3\x4f"
+ "\x92\xdf\x24\x76\x75\x98\x13\x5c\xee\x4f\xd3\x94\xb9\x38\x9b\x81\x2c\x40"
+ "\xf1\x94\xe6\xb2\x5c\x6e\x0a\x83\xfe\xb6\x45\x43\x32\xe2\x28\x36\x62\xe3"
+ "\xf3\xe1\x90\xf8\xf1\xee\xa8\xa4\xd9\xa1\x0a\xcb\x4d\x68\x24\x2c\x46\x5f"
+ "\x69\x3d\x91\xad\xbe\x00\x00\x54\x00\x02\x80\x08\x00\x01\x80\x00\x00\x00"
+ "\x00\x08\x00\x01\x80\x89\x60\x53\xcd\x09\x00\x02\x00\x73\x79\x7a\x30\x00"
+ "\x00\x00\x00\x09\x00\x02\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00\x01"
+ "\x80\xff\xff\xff\xfe\x09\x00\x02\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08"
+ "\x00\x01\x80\x22\x1e\xf5\xdc\x09\x00\x02\x00\x73\x79\x7a\x30\x00\x00\x00"
+ "\x00\x48\x00\x02\x80\x09\x00\x02\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x09"
+ "\x00\x02\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00\x01\x80\xff\xff\xff"
+ "\xfe\x08\x00\x02\x00\x00\xff\xff\xfc\x09\x00\x02\x00\x73\x79\x7a\x32\x00"
+ "\x00\x00\x00\x08\x00\x01\x80\x00\x00\x00\x00\x08\x00\x01\x80\x00\x00\x00"
+ "\x00\x78\x01\x01\x00\x0b\x5c\x35\xc8\x6c\x0b\xc4\x0d\x2b\x12\x02\xa7\xb4"
+ "\x07\x79\xcd\xe9\x4f\x38\xfb\x12\x01\xf5\x4f\x14\x42\x60\xf6\x52\xf5\x91"
+ "\x67\x7d\x84\xbe\xee\xe1\xfa\xd9\xf0\x16\xf5\xdb\xa2\x0e\xe8\xc3\xe7\x73"
+ "\x51\x98\x08\x55\xff\xd0\xee\xed\x14\xfe\xc0\xab\x64\x54\xa0\x1e\xc0\xf9"
+ "\xd0\x97\x34\xad\xd6\xf1\x1a\x23\x65\xe7\x1d\xc5\x8e\xcf\xdc\xdc\x05\xea"
+ "\x8c\x20\x28\xbc\x70\x15\x77\x8e\xc7\x1b\xb0\x13\xf6\x25\x03\x79\x3a\x67"
+ "\xba\xc4\xf6\x45\x52\x27\x7e\x89\xb2\x9c\x36\xed\xe3\xd5\x07\xff\x09\x5a"
+ "\x73\xb5\xdc\xbc\x18\x0a\x27\x7b\xee\x21\xf7\x34\x74\x38\xa7\x22\x20\x85"
+ "\xe7\x1a\xac\xb9\x66\x8d\xaa\x4f\x03\x87\x2b\xd6\x25\x67\x55\x38\x40\x57"
+ "\xd4\x85\xf6\x85\x37\xb2\xf6\x02\xd6\x38\x93\xeb\xa0\x49\x02\xd0\x26\xc0"
+ "\x27\xf9\x72\xfb\xa7\xa6\x36\xbc\x4f\x4e\xc3\xcb\x77\xdb\x05\xa5\x66\x3a"
+ "\x1a\x21\x01\xed\x0a\xe8\x76\xbb\x21\x02\x2d\xf5\xb1\xb6\xb8\x19\xe7\x1a"
+ "\xa0\x80\x48\x25\xed\x4f\x56\x2e\x15\xbd\xc6\xab\xab\x82\xe9\x9c\x37\x2a"
+ "\xfb\x97\x45\x78\x85\x96\x33\x0f\xe5\x73\x29\xe3\x8a\xa8\xda\x6e\x2f\x02"
+ "\xf0\x6f\x09\xc0\xf0\x75\x94\x92\x21\xb1\xc4\x72\x97\x68\x8f\xf2\x31\x15"
+ "\xd9\x02\xd6\xc7\x40\x7b\xd3\xc4\xaf\x3b\x0c\x4c\xb5\x88\x88\x5d\x21\x25"
+ "\xb3\x91\x12\x98\xf1\x55\x12\xc8\x4c\x07\xa4\x5c\x2c\x32\xa1\xe9\x56\x6f"
+ "\x66\xdf\x0a\x31\x50\xf6\xa9\xf6\x90\xb5\x09\xdc\x13\x3f\x47\xb2\x7b\xee"
+ "\x5e\xc2\xe4\xd7\xe7\x6d\x78\xe9\x26\x23\xa9\x83\x8b\x66\x80\xc4\x90\x97"
+ "\x3e\x66\x76\xdd\x46\x04\xd4\x8d\x5b\x0d\xc3\x6b\xbb\xbe\x18\x96\xe7\x4d"
+ "\xe3\x5a\x97\x19\xcc\xe3\xc3\xc5\xd9\x3c\x34\xd1\xd8\x35\xbb\x65\xcc\xe1"
+ "\x00\x01\x00\x2e\x56\x2b\x5c\x28\x8e\xa9\xd2\x7b\x17\x78\x5a\x8b\x0a\x77"
+ "\xb3\x1a\x26\x21\x80\xdb\x12\x8c\xcc\x1a\xf4\xb9\x58\x92\xcd\xc3\x42\x5d"
+ "\xf9\x03\x06\xa5\x19\x65\xa9\x89\xce\x05\x2c\xd9\x77\x10\xd9\xf6\xa3\xd5"
+ "\xe1\x82\x14\x9e\x80\x84\xdc\xea\xe5\x63\x36\x12\x79\xa4\x3c\xcb\xf2\x01"
+ "\x4e\xa6\x72\x2e\xa5\xff\x99\x0f\xd8\x41\x9c\x61\x95\x56\x75\xfe\x14\x90"
+ "\x91\x1d\x00\x3d\x9b\x70\xf7\x1f\xee\xb4\x0d\x5e\x57\x19\xf4\x08\x4a\x56"
+ "\x58\x53\x51\xe4\x63\xe6\x17\x04\xb0\xdc\x00\x01\x81\xff\xd8\xfb\xff\xaf"
+ "\xf9\x0b\x6b\xd5\x4a\x3c\xa5\x8f\xa0\xfe\xf9\x74\x8c\xdd\x29\x32\xdc\x89"
+ "\xd9\xec\x45\x8e\xe0\x18\xfd\xcc\xbc\xb1\x26\xca\xcd\xc2\x5c\xca\x4f\xd7"
+ "\x66\xe5\x7d\x48\x73\xd5\xdb\xfd\x2b\xc3\x21\xdc\x34\xb6\x79\x26\x5d\x30"
+ "\x97\x67\x1d\x07\x4c\x0b\x9b\x8e\xfe\xaf\xed\x5e\xaa\x06\x77\xcd\x74\xd8"
+ "\xb2\x37\x01\x2f\x68\xc9\xa5\x58\x9d\xc1\xbb\x5a\xfa\x0d\x47\xe7\x0a\x98"
+ "\x80\x9f\x96\x66\x45\xeb\x89\x12\x00\x00\x00\x14\x00\x00\x00\x11\x00\x01"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x85\xd5\xae\x25\xb2"
+ "\x98\x60\xd2\x85\x33\x93\x50\x0a\x79\xc9\x80\x06\x27\x65\x1a\x97\xd1\x8d"
+ "\x10\x01\x91\x1d\x4f\x83\x1b\x7f\x92\xe8\x04\x72\x33\xec\xef\xc2\x20\x0c"
+ "\x88\x69\x67\x93\x74\x31\xf1\x41\x1b\x6f\x69\x1d\x22\xc4\x8f\xd6\x37\xde"
+ "\x4c\x93\xc5\x2e\xa2\x03\xc5\xcc\x47\xfb\x87\x31\x07\x31\x56\xab\x63\x40"
+ "\x64\x06\x45\x55\x6a\x45\xa8\x49\x18\xc4\xfa\x8b\x17\x59\x63\xba\x75\x6e"
+ "\xa0\x22\xdd\xd2\x5f\x87\x67\x75\x45\xc0\x56\xe1\x27\x6e\xb7\x76\x93\x45"
+ "\x98\x8c\xf6\xff\x02\xd3\xce\x83\x69\xf4\xa8\x30\x32\x08\xff\xae\xb9\x62"
+ "\xb1\xfa\x71\x57\xbe\x4c\x77\x18\x29\xd1\xa2\x41\xd5\xf7\x07\xf8\x8b\x45"
+ "\x48\xb2\xa0\x20\xdd\xda\xee\x13\x91\x4f\xd0\xac\x78\x88\xb8\x40\xf8\xd4"
+ "\x69\x8d\xe1\x3b\x58\x5f\x5b\xa3\x55\x12\x38\xf8\xa9\xce\xf1\xd0\x92\x3b"
+ "\x23\x19\xd6\x5c\xe6\xc0\x3f\x11\x69\xc4\x72\x4c\x0c",
+ 1543);
+ *(uint64_t*)0x20000208 = 0x540;
+ *(uint64_t*)0x20000258 = 1;
+ *(uint64_t*)0x20000260 = 0;
+ *(uint64_t*)0x20000268 = 0;
+ *(uint32_t*)0x20000270 = 0;
+ syscall(__NR_sendmsg, r[2], 0x20000240ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/a61c70e69cc9cbf670a632d0fd1457d3718c66f8.c b/syzkaller-repros/linux/a61c70e69cc9cbf670a632d0fd1457d3718c66f8.c
new file mode 100644
index 0000000..73947e0
--- /dev/null
+++ b/syzkaller-repros/linux/a61c70e69cc9cbf670a632d0fd1457d3718c66f8.c
@@ -0,0 +1,459 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_perf_event_open, 0ul, 0, 0ul, -1, 0ul);
+ res = syz_open_dev(0xc, 4, 0x14);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000100,
+ "\x82\xaf\xa5\x1d\x23\x73\x70\x78\x3c\xd2\x55\x7c\x70\xa9\x3d\xf1\xbd"
+ "\xf3\x7b\x3d\x42\x89\xe8\x85\xa1\xe9\xf2\x54\x4b\x74\x17\x96\xf4\xdb"
+ "\xc9\x81\xec\x3d\x8e\xf5\x96\x02\x52\x2d\xf4\xdc\x34\xa4\x48\xd5\x19"
+ "\x5a\x10\x61\xba\xdd\x08\xfd\xd0\x53",
+ 60);
+ inject_fault(18);
+ syscall(__NR_ioctl, r[0], 0x4b61ul, 0x20000100ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/a82ff8cfa42fa8b5986b3ff2454f2e435a2a8706.c b/syzkaller-repros/linux/a82ff8cfa42fa8b5986b3ff2454f2e435a2a8706.c
new file mode 100644
index 0000000..f6e950b
--- /dev/null
+++ b/syzkaller-repros/linux/a82ff8cfa42fa8b5986b3ff2454f2e435a2a8706.c
@@ -0,0 +1,441 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x200001c0, "/dev/ptmx\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200001c0ul, 2ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000040, "\xe0", 1);
+ inject_fault(1);
+ syscall(__NR_write, r[0], 0x20000040ul, 0xfffffe00ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/a8ad6862817edd0b631f8547843c684f45e09bd1.c b/syzkaller-repros/linux/a8ad6862817edd0b631f8547843c684f45e09bd1.c
new file mode 100644
index 0000000..b0d9203
--- /dev/null
+++ b/syzkaller-repros/linux/a8ad6862817edd0b631f8547843c684f45e09bd1.c
@@ -0,0 +1,321 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 6; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+#ifndef __NR_clone3
+#define __NR_clone3 435
+#endif
+
+uint64_t r[3] = {0xffffffffffffffff, 0x0, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000080, "./bus\000", 6);
+ res = syscall(__NR_creat, 0x20000080ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_ftruncate, r[0], 0x208200ul);
+ break;
+ case 2:
+ *(uint64_t*)0x20001540 = 0;
+ *(uint64_t*)0x20001548 = 0;
+ *(uint64_t*)0x20001550 = 0;
+ *(uint64_t*)0x20001558 = 0;
+ *(uint32_t*)0x20001560 = 0;
+ *(uint64_t*)0x20001568 = 0;
+ *(uint64_t*)0x20001570 = 0;
+ *(uint64_t*)0x20001578 = 0;
+ *(uint64_t*)0x20001580 = 0;
+ *(uint64_t*)0x20001588 = 0;
+ res = syscall(__NR_clone3, 0x20001540ul, 0x40ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ *(uint64_t*)0x200026c0 = 0x20000240;
+ *(uint64_t*)0x200026c8 = 0xfffffe54;
+ syscall(__NR_process_vm_writev, r[1], 0x200026c0ul, 1ul, 0x20000200ul,
+ 0x369ul, 0ul);
+ break;
+ case 4:
+ memcpy((void*)0x20000400, "./bus\000", 6);
+ res = syscall(__NR_open, 0x20000400ul, 0x14103eul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 5:
+ syscall(__NR_mmap, 0x20000000ul, 0x600000ul, 0x7ffffeul, 0x11ul, r[2], 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/ab2ce52e17c561fe15b48290dd8f0f31770983f3.c b/syzkaller-repros/linux/ab2ce52e17c561fe15b48290dd8f0f31770983f3.c
new file mode 100644
index 0000000..82d4b56
--- /dev/null
+++ b/syzkaller-repros/linux/ab2ce52e17c561fe15b48290dd8f0f31770983f3.c
@@ -0,0 +1,363 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syz_open_dev(0, 0, 2);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ NONFAILING(*(uint32_t*)0x20000040 = 2);
+ syscall(__NR_ioctl, r[0], 0xc0045627, 0x20000040);
+ break;
+ case 2:
+ NONFAILING(memcpy((void*)0x20000140, "/dev/vbi#\000", 10));
+ res = syz_open_dev(0x20000140, 0, 2);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ syscall(__NR_read, r[1], 0x200000c0, 0x1000001b2);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ install_segv_handler();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/aba7fea369c95764f5bdb4bde7d65c40bb033de9.c b/syzkaller-repros/linux/aba7fea369c95764f5bdb4bde7d65c40bb033de9.c
new file mode 100644
index 0000000..9d0752d
--- /dev/null
+++ b/syzkaller-repros/linux/aba7fea369c95764f5bdb4bde7d65c40bb033de9.c
@@ -0,0 +1,117 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static void execute_one();
+extern unsigned long long procid;
+
+void loop()
+{
+ while (1) {
+ execute_one();
+ }
+}
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+void execute_call(int call)
+{
+ switch (call) {
+ case 0:
+ syscall(__NR_dup3, 0xffffff9c, 0xffffff9c, 0);
+ break;
+ case 1:
+ syscall(__NR_munlockall);
+ break;
+ case 2:
+ memcpy((void*)0x20000080, "./file0", 8);
+ syscall(__NR_mkdir, 0x20000080, 0);
+ break;
+ case 3:
+ memcpy((void*)0x20000040, "./file0", 8);
+ syscall(__NR_chroot, 0x20000040);
+ break;
+ case 4:
+ memcpy((void*)0x20000000, ".", 2);
+ syscall(__NR_chroot, 0x20000000);
+ break;
+ }
+}
+
+void execute_one()
+{
+ execute(5);
+ collide = 1;
+ execute(5);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (;;) {
+ loop();
+ }
+}
diff --git a/syzkaller-repros/linux/ac95a2efec88d8b83a87f1d7b75dee8adbe605bc.c b/syzkaller-repros/linux/ac95a2efec88d8b83a87f1d7b75dee8adbe605bc.c
new file mode 100644
index 0000000..408a01b
--- /dev/null
+++ b/syzkaller-repros/linux/ac95a2efec88d8b83a87f1d7b75dee8adbe605bc.c
@@ -0,0 +1,294 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000240, "./file1\000", 8);
+ syscall(__NR_mkdir, 0x20000240ul, 0ul);
+ memcpy((void*)0x20000180, "./bus\000", 6);
+ syscall(__NR_mkdir, 0x20000180ul, 0ul);
+ memcpy((void*)0x20000280, "./file0\000", 8);
+ syscall(__NR_mkdir, 0x20000280ul, 0ul);
+ memcpy((void*)0x20000000, "./bus\000", 6);
+ memcpy((void*)0x20000080, "overlay\000", 8);
+ memcpy((void*)0x20000100, "lowerdir=./bus,workdir=./file1,upperdir=./file0",
+ 47);
+ syscall(__NR_mount, 0x400000ul, 0x20000000ul, 0x20000080ul, 0ul,
+ 0x20000100ul);
+ memcpy((void*)0x200002c0, "./bus\000", 6);
+ syscall(__NR_chdir, 0x200002c0ul);
+ res = syscall(__NR_socket, 0xaul, 0x400000000001ul, 0);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x209e1000, "./file0\000", 8);
+ res = syscall(__NR_open, 0x209e1000ul, 0x8060ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_fcntl, r[1], 0x400ul, 1ul);
+ syscall(__NR_sendfile, r[0], r[1], 0ul, 0x800000000024ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/ad8204ca57a1325744c730504d3a1db01b02ece7.c b/syzkaller-repros/linux/ad8204ca57a1325744c730504d3a1db01b02ece7.c
new file mode 100644
index 0000000..cbe74b7
--- /dev/null
+++ b/syzkaller-repros/linux/ad8204ca57a1325744c730504d3a1db01b02ece7.c
@@ -0,0 +1,899 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/usb/ch9.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(int sock, const char* name, const void* addr,
+ int addrsize, const void* mac, int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ netlink_attr(NDA_DST, addr, addrsize);
+ netlink_attr(NDA_LLADDR, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+#define SYZ_TUN_MAX_PACKET_SIZE 1000
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in_addr, sizeof(in_addr), &macaddr,
+ ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in6_addr, sizeof(in6_addr), &macaddr,
+ ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_binfmt_misc();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define SYZ_HAVE_CLOSE_FDS 1
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+void loop(void)
+{
+ NONFAILING(*(uint8_t*)0x20000000 = 0x12);
+ NONFAILING(*(uint8_t*)0x20000001 = 1);
+ NONFAILING(*(uint16_t*)0x20000002 = 0);
+ NONFAILING(*(uint8_t*)0x20000004 = 0xc2);
+ NONFAILING(*(uint8_t*)0x20000005 = 0x73);
+ NONFAILING(*(uint8_t*)0x20000006 = 0x60);
+ NONFAILING(*(uint8_t*)0x20000007 = 8);
+ NONFAILING(*(uint16_t*)0x20000008 = 0xbda);
+ NONFAILING(*(uint16_t*)0x2000000a = 0x8713);
+ NONFAILING(*(uint16_t*)0x2000000c = 0x17db);
+ NONFAILING(*(uint8_t*)0x2000000e = 0);
+ NONFAILING(*(uint8_t*)0x2000000f = 0);
+ NONFAILING(*(uint8_t*)0x20000010 = 0);
+ NONFAILING(*(uint8_t*)0x20000011 = 1);
+ NONFAILING(*(uint8_t*)0x20000012 = 9);
+ NONFAILING(*(uint8_t*)0x20000013 = 2);
+ NONFAILING(*(uint16_t*)0x20000014 = 0x12);
+ NONFAILING(*(uint8_t*)0x20000016 = 1);
+ NONFAILING(*(uint8_t*)0x20000017 = 0);
+ NONFAILING(*(uint8_t*)0x20000018 = 0);
+ NONFAILING(*(uint8_t*)0x20000019 = 0);
+ NONFAILING(*(uint8_t*)0x2000001a = 0);
+ NONFAILING(*(uint8_t*)0x2000001b = 9);
+ NONFAILING(*(uint8_t*)0x2000001c = 4);
+ NONFAILING(*(uint8_t*)0x2000001d = 0xba);
+ NONFAILING(*(uint8_t*)0x2000001e = 0);
+ NONFAILING(*(uint8_t*)0x2000001f = 0);
+ NONFAILING(*(uint8_t*)0x20000020 = 0x4b);
+ NONFAILING(*(uint8_t*)0x20000021 = 0xeb);
+ NONFAILING(*(uint8_t*)0x20000022 = 0xd6);
+ NONFAILING(*(uint8_t*)0x20000023 = 0);
+ syz_usb_connect(0x8000002, 0x24, 0x20000000, 0);
+ close_fds();
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ install_segv_handler();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/aeedb5a72e90166ad43d01ef7903a82e3bb152f2.c b/syzkaller-repros/linux/aeedb5a72e90166ad43d01ef7903a82e3bb152f2.c
new file mode 100644
index 0000000..6d1a4a5
--- /dev/null
+++ b/syzkaller-repros/linux/aeedb5a72e90166ad43d01ef7903a82e3bb152f2.c
@@ -0,0 +1,221 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x11, 3, 0x300);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20000140 = 0;
+ *(uint8_t*)0x20000142 = 0;
+ *(uint8_t*)0x20000143 = 0xd7;
+ syscall(__NR_setsockopt, r[0], 0x107, 0x12, 0x20000140, 4);
+ res = syscall(__NR_socket, 0x11, 3, 0x300);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x20000140 = 0;
+ *(uint8_t*)0x20000142 = 0;
+ *(uint8_t*)0x20000143 = 0xd7;
+ syscall(__NR_setsockopt, r[1], 0x107, 0x12, 0x20000140, 4);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/aef49c1a69a0735d29caaaddc7819aaed6c8c501.c b/syzkaller-repros/linux/aef49c1a69a0735d29caaaddc7819aaed6c8c501.c
new file mode 100644
index 0000000..0ba17d8
--- /dev/null
+++ b/syzkaller-repros/linux/aef49c1a69a0735d29caaaddc7819aaed6c8c501.c
@@ -0,0 +1,1083 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+#ifndef __NR_io_uring_register
+#define __NR_io_uring_register 427
+#endif
+#ifndef __NR_io_uring_setup
+#define __NR_io_uring_setup 425
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint32_t*)0x200000b8 = 0;
+ *(uint32_t*)0x200000bc = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint64_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ *(uint32_t*)0x200000e0 = 0;
+ *(uint32_t*)0x200000e4 = 0;
+ *(uint32_t*)0x200000e8 = 0;
+ *(uint32_t*)0x200000ec = 0;
+ *(uint64_t*)0x200000f0 = 0;
+ res = syscall(__NR_io_uring_setup, 0xa4, 0x20000080ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000280 = -1;
+ *(uint32_t*)0x20000284 = -1;
+ *(uint32_t*)0x20000288 = -1;
+ syscall(__NR_io_uring_register, r[0], 2ul, 0x20000280ul,
+ 0x40000000000000a1ul);
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0x302ul, 0ul);
+ syscall(__NR_ioctl, -1, 0x2284ul, 0ul);
+ syscall(__NR_sendmmsg, -1, 0ul, 0ul, 0ul);
+ syscall(__NR_gettid);
+ syscall(__NR_socket, 0ul, 2ul, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/aff4be9963d14b033e496164b2fdb16fd437bbe8.c b/syzkaller-repros/linux/aff4be9963d14b033e496164b2fdb16fd437bbe8.c
new file mode 100644
index 0000000..93096ed
--- /dev/null
+++ b/syzkaller-repros/linux/aff4be9963d14b033e496164b2fdb16fd437bbe8.c
@@ -0,0 +1,449 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+void execute_one(void)
+{
+ *(uint8_t*)0x20000000 = 0x12;
+ *(uint8_t*)0x20000001 = 1;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint8_t*)0x20000004 = 0x98;
+ *(uint8_t*)0x20000005 = 0x86;
+ *(uint8_t*)0x20000006 = 0xf6;
+ *(uint8_t*)0x20000007 = 8;
+ *(uint16_t*)0x20000008 = 0x2201;
+ *(uint16_t*)0x2000000a = 0x12c;
+ *(uint16_t*)0x2000000c = 0xc1e7;
+ *(uint8_t*)0x2000000e = 0;
+ *(uint8_t*)0x2000000f = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 1;
+ *(uint8_t*)0x20000012 = 9;
+ *(uint8_t*)0x20000013 = 2;
+ *(uint16_t*)0x20000014 = 0x12;
+ *(uint8_t*)0x20000016 = 1;
+ *(uint8_t*)0x20000017 = 0;
+ *(uint8_t*)0x20000018 = 0;
+ *(uint8_t*)0x20000019 = 0;
+ *(uint8_t*)0x2000001a = 0;
+ *(uint8_t*)0x2000001b = 9;
+ *(uint8_t*)0x2000001c = 4;
+ *(uint8_t*)0x2000001d = 0x67;
+ *(uint8_t*)0x2000001e = 0;
+ *(uint8_t*)0x2000001f = 0;
+ *(uint8_t*)0x20000020 = 0xa4;
+ *(uint8_t*)0x20000021 = 0x3e;
+ *(uint8_t*)0x20000022 = 0x8f;
+ *(uint8_t*)0x20000023 = 0;
+ syz_usb_connect(0x20000b, 0x24, 0x20000000, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/aff5959c1d4af7564287846f796ff7b8462352ed.c b/syzkaller-repros/linux/aff5959c1d4af7564287846f796ff7b8462352ed.c
new file mode 100644
index 0000000..c57f78b
--- /dev/null
+++ b/syzkaller-repros/linux/aff5959c1d4af7564287846f796ff7b8462352ed.c
@@ -0,0 +1,668 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+static long syz_init_net_socket(volatile long domain, volatile long type,
+ volatile long proto)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ return netns;
+ if (setns(kInitNetNsFd, 0))
+ return -1;
+ int sock = syscall(__NR_socket, domain, type, proto);
+ int err = errno;
+ if (setns(netns, 0))
+ exit(1);
+ close(netns);
+ errno = err;
+ return sock;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_perf_event_open, 0, 0, -1, -1, 0);
+ syz_init_net_socket(0xb, 5, 0);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x531e, 0);
+ res = syscall(__NR_socket, 0xa, 6, 0);
+ if (res != -1)
+ r[1] = res;
+ NONFAILING(*(uint16_t*)0x20000000 = 0xa);
+ NONFAILING(*(uint16_t*)0x20000002 = htobe16(0x4e23));
+ NONFAILING(*(uint32_t*)0x20000004 = htobe32(0));
+ NONFAILING(memcpy(
+ (void*)0x20000008,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16));
+ NONFAILING(*(uint32_t*)0x20000018 = 0);
+ syscall(__NR_bind, r[1], 0x20000000, 0x1c);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x20000, 0);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_write, r[2], 0, 0);
+ syscall(__NR_listen, r[1], 0x5eb856);
+ res = syscall(__NR_socket, 2, 6, 0);
+ if (res != -1)
+ r[3] = res;
+ NONFAILING(*(uint16_t*)0x20000340 = 2);
+ NONFAILING(*(uint16_t*)0x20000342 = htobe16(0x4e23));
+ NONFAILING(*(uint32_t*)0x20000344 = htobe32(0));
+ inject_fault(10);
+ syscall(__NR_connect, r[3], 0x20000340, 0x10);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ setup_fault();
+ install_segv_handler();
+ use_temporary_dir();
+ do_sandbox_none();
+ check_leaks();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b06c3d8398b9cdd888c8404b690cb7aa3ec1b0fc.c b/syzkaller-repros/linux/b06c3d8398b9cdd888c8404b690cb7aa3ec1b0fc.c
new file mode 100644
index 0000000..1258a64
--- /dev/null
+++ b/syzkaller-repros/linux/b06c3d8398b9cdd888c8404b690cb7aa3ec1b0fc.c
@@ -0,0 +1,231 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/vhost-net\000", 15);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000000, 2, 0);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x40000000af01, 0);
+ memcpy((void*)0x20000080, "/dev/net/tun\000", 13);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000080, 0, 0);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000300, "bctf0\000\000\000\000\000\000\"\000\000\000\000",
+ 16);
+ *(uint16_t*)0x20000310 = 6;
+ syscall(__NR_ioctl, r[1], 0x400454ca, 0x20000300);
+ *(uint32_t*)0x20000240 = 1;
+ *(uint32_t*)0x20000244 = 0;
+ *(uint64_t*)0x20000248 = 0;
+ *(uint64_t*)0x20000250 = 0x200019c0;
+ *(uint64_t*)0x20000258 = 0;
+ *(uint64_t*)0x20000260 = 0;
+ syscall(__NR_ioctl, r[0], 0x4028af11, 0x20000240);
+ syscall(__NR_ioctl, r[0], 0x4008af03, 0x200007c0);
+ *(uint32_t*)0x200000c0 = 1;
+ *(uint32_t*)0x200000c4 = r[1];
+ syscall(__NR_ioctl, r[0], 0x4008af30, 0x200000c0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b15b71cdbabd376770788544e17a585a9ed0de7e.c b/syzkaller-repros/linux/b15b71cdbabd376770788544e17a585a9ed0de7e.c
new file mode 100644
index 0000000..a5eb7a6
--- /dev/null
+++ b/syzkaller-repros/linux/b15b71cdbabd376770788544e17a585a9ed0de7e.c
@@ -0,0 +1,377 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint64_t*)0x20000280 = 0;
+ *(uint32_t*)0x20000288 = 0x2d3;
+ *(uint64_t*)0x20000290 = 0x20000240;
+ *(uint64_t*)0x20000240 = 0x200002c0;
+ memcpy(
+ (void*)0x200002c0,
+ "\x14\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00"
+ "\x00\x00\x0a\x20\x00\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00"
+ "\x00\x70\x00\x00\x00\x12\x0a\x01\x00\x00\x1f\x34\x01\x04\x00\x00\x00"
+ "\x00\x00\x00\x00\x04\x00\x04\x80\x09\x00\x02\x00\x73\x79\x7a\x30\x00"
+ "\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00"
+ "\x03\x40\x00\x00\x00\x00\x22\x00\x02\x00\xb7\x63\x12\xc4\x11\x0d\xd9"
+ "\xb1\x73\x79\xe7\x28\x14\x7a\xfe\x6a\xb9\xf3\x2a\xa9\xd1\x45\x00\x04"
+ "\x80\x00\x00\x04\x00\x06\x14\x00\x04\x80\x09\x00\x01\x00\x59\x79\x7a"
+ "\x30\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x11\x00\x6d\x30\xa1\x6e"
+ "\x90\x01\x6c\x47\x8a\x50\x48\x3a\x73\x64\x5a\x6d\xc4\xb5\x34\x5d\x2c"
+ "\x0d\xb7\x4c\x9f\x89\x67\x8f\xbc\x9c\xc6\xfb\x9e\x8e\x31\xfa\xd7\xe7"
+ "\x58\x0e\x6a\xe4\x35\x8d\x8f\x95\xa2\x73\x5d\x57\xdc\x6e\x3a\xf5\xcf"
+ "\x3e\xd7\xaa\x68\xb1\x91\xfe\xa4\x67\x66\xe9\xa1\xb3\xb4\xc9\xb0\x75"
+ "\xf7\x4c\x98\x1f\x80\x44\x53\x89\x8a\x0b\x8f\x9d\x08\x1e\xf6\x43\x7d"
+ "\x40\x51\xa3\x1e\xff\xff\x78\x44\x21\xe4\x78\xa6\xe0\x4e\x0f\xb3\x69"
+ "\xef\x95\xf2\x89\xff\x35\xa2\x43\x34\xba\x0d\x5a\xc0\x37\x02\x8b\x66"
+ "\x59\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 300);
+ *(uint64_t*)0x20000248 = 0xb8;
+ *(uint64_t*)0x20000298 = 1;
+ *(uint64_t*)0x200002a0 = 0;
+ *(uint64_t*)0x200002a8 = 0;
+ *(uint32_t*)0x200002b0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000280ul, 0ul);
+ break;
+ case 2:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ *(uint64_t*)0x20006480 = 0;
+ *(uint32_t*)0x20006488 = 0;
+ *(uint64_t*)0x20006490 = 0x20006440;
+ *(uint64_t*)0x20006440 = 0x200064c0;
+ *(uint32_t*)0x200064c0 = 0x14;
+ *(uint16_t*)0x200064c4 = 0x10;
+ *(uint16_t*)0x200064c6 = 1;
+ *(uint32_t*)0x200064c8 = 0;
+ *(uint32_t*)0x200064cc = 0;
+ *(uint8_t*)0x200064d0 = 0;
+ *(uint8_t*)0x200064d1 = 0;
+ *(uint16_t*)0x200064d2 = htobe16(0xa);
+ *(uint32_t*)0x200064d4 = 0x14;
+ *(uint8_t*)0x200064d8 = 2;
+ *(uint8_t*)0x200064d9 = 0xa;
+ *(uint16_t*)0x200064da = 0x301;
+ *(uint32_t*)0x200064dc = 0;
+ *(uint32_t*)0x200064e0 = 0;
+ *(uint8_t*)0x200064e4 = 0;
+ *(uint8_t*)0x200064e5 = 0;
+ *(uint16_t*)0x200064e6 = htobe16(0);
+ *(uint32_t*)0x200064e8 = 0x20;
+ *(uint8_t*)0x200064ec = 0;
+ *(uint8_t*)0x200064ed = 0xa;
+ *(uint16_t*)0x200064ee = 0x101;
+ *(uint32_t*)0x200064f0 = 0;
+ *(uint32_t*)0x200064f4 = 0;
+ *(uint8_t*)0x200064f8 = 0;
+ *(uint8_t*)0x200064f9 = 0;
+ *(uint16_t*)0x200064fa = htobe16(0);
+ *(uint16_t*)0x200064fc = 9;
+ *(uint16_t*)0x200064fe = 1;
+ memcpy((void*)0x20006500, "syz1\000", 5);
+ *(uint32_t*)0x20006508 = 0x14;
+ *(uint16_t*)0x2000650c = 0x11;
+ *(uint16_t*)0x2000650e = 1;
+ *(uint32_t*)0x20006510 = 0;
+ *(uint32_t*)0x20006514 = 0;
+ *(uint8_t*)0x20006518 = 0;
+ *(uint8_t*)0x20006519 = 0;
+ *(uint16_t*)0x2000651a = htobe16(0xa);
+ *(uint64_t*)0x20006448 = 0x5c;
+ *(uint64_t*)0x20006498 = 1;
+ *(uint64_t*)0x200064a0 = 0;
+ *(uint64_t*)0x200064a8 = 0;
+ *(uint32_t*)0x200064b0 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20006480ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b1749b0ecbd1cc9fb2350136237de3217b0a6877.c b/syzkaller-repros/linux/b1749b0ecbd1cc9fb2350136237de3217b0a6877.c
new file mode 100644
index 0000000..b9cec33
--- /dev/null
+++ b/syzkaller-repros/linux/b1749b0ecbd1cc9fb2350136237de3217b0a6877.c
@@ -0,0 +1,375 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void loop(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 6; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint64_t*)0x20000280 = 0;
+ *(uint32_t*)0x20000288 = 0x2d3;
+ *(uint64_t*)0x20000290 = 0x20000240;
+ *(uint64_t*)0x20000240 = 0x200002c0;
+ memcpy(
+ (void*)0x200002c0,
+ "\x14\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00"
+ "\x00\x00\x0a\x20\x00\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00"
+ "\x00\x70\x00\x00\x00\x12\x0a\x01\x00\x00\x1f\x34\x01\x04\x00\x00\x00"
+ "\x00\x00\x00\x00\x04\x00\x04\x80\x09\x00\x02\x00\x73\x79\x7a\x30\x00"
+ "\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00"
+ "\x03\x40\x00\x00\x00\x00\x22\x00\x02\x00\xb7\x63\x12\xc4\x11\x0d\xd9"
+ "\xb1\x73\x79\xe7\x28\x14\x7a\xfe\x6a\xb9\xf3\x2a\xa9\xd1\x00\x04\x80"
+ "\x00\x00\x04\x00\x06\x14\x00\x04\x80\x09\x00\x01\x00\x59\x79\x7a\x30"
+ "\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x11\x00\x6d\x30\xa1\x6e\x90"
+ "\x01\x6c\x47\x8a\x50\x48\x3a\x73\x64\x5a\x6d\xc4\xb5\x34\x5d\x2c\x0d"
+ "\xb7\x4c\x9f\x89\x67\x8f\xbc\x9c\xc6\xfb\x9e\x8e\x31\xfa\xd7\xe7\x58"
+ "\x0e\x6a\xe4\x35\x8d\x8f\x95\xa2\x73\x5d\x57\xdc\x6e\x3a\xf5\xcf\x3e"
+ "\x09\xaa\x68\xb1\x91\xfe\xa4\x67\x66\xe9\xa1\xb3\xb4\xc9\xb0\x75\xf7"
+ "\x4c\x98\x1f\x80\x44\x53\x89\x8a\x0b\x8f\x9d\x08\x1e\xf6\x43\x7d\x40"
+ "\x51\xa3\x1e\xef\xf8\x78\x44\x21\xe4\x78\xa6\xe0\x4e\x0f\xb3\x69\xef"
+ "\x95\xf2\x89\xff\x35\xa2\x43\x34\xba\x0d\x5a\xc0\x37\x02\x8b\x66\x59"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 299);
+ *(uint64_t*)0x20000248 = 0xb8;
+ *(uint64_t*)0x20000298 = 1;
+ *(uint64_t*)0x200002a0 = 0;
+ *(uint64_t*)0x200002a8 = 0;
+ *(uint32_t*)0x200002b0 = 0;
+ syscall(__NR_sendmsg, -1, 0x20000280ul, 0ul);
+ break;
+ case 2:
+ *(uint64_t*)0x20000600 = 0x20000500;
+ *(uint16_t*)0x20000500 = 0x10;
+ *(uint16_t*)0x20000502 = 0;
+ *(uint32_t*)0x20000504 = 0;
+ *(uint32_t*)0x20000508 = 0x80001100;
+ *(uint32_t*)0x20000608 = 0xc;
+ *(uint64_t*)0x20000610 = 0x200005c0;
+ *(uint64_t*)0x200005c0 = 0x20000540;
+ *(uint32_t*)0x20000540 = 0x60;
+ *(uint8_t*)0x20000544 = 2;
+ *(uint8_t*)0x20000545 = 7;
+ *(uint16_t*)0x20000546 = 0x101;
+ *(uint32_t*)0x20000548 = 0;
+ *(uint32_t*)0x2000054c = 0;
+ *(uint8_t*)0x20000550 = 0xa;
+ *(uint8_t*)0x20000551 = 0;
+ *(uint16_t*)0x20000552 = htobe16(3);
+ *(uint16_t*)0x20000554 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000556, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000557, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000557, 0, 7, 1);
+ *(uint64_t*)0x20000558 = htobe64(4);
+ *(uint16_t*)0x20000560 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000562, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000563, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000563, 0, 7, 1);
+ *(uint64_t*)0x20000564 = htobe64(0);
+ *(uint16_t*)0x2000056c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000056e, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000056f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000056f, 0, 7, 1);
+ *(uint32_t*)0x20000570 = htobe32(3);
+ *(uint16_t*)0x20000574 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000576, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000577, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000577, 0, 7, 1);
+ *(uint64_t*)0x20000578 = htobe64(2);
+ *(uint16_t*)0x20000580 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000582, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000583, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000583, 0, 7, 1);
+ *(uint32_t*)0x20000584 = htobe32(0);
+ *(uint16_t*)0x20000588 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000058a, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000058b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000058b, 0, 7, 1);
+ *(uint64_t*)0x2000058c = htobe64(0xffff);
+ *(uint16_t*)0x20000594 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000596, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000597, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000597, 0, 7, 1);
+ *(uint64_t*)0x20000598 = htobe64(0x39c);
+ *(uint64_t*)0x200005c8 = 0x60;
+ *(uint64_t*)0x20000618 = 1;
+ *(uint64_t*)0x20000620 = 0;
+ *(uint64_t*)0x20000628 = 0;
+ *(uint32_t*)0x20000630 = 0x10;
+ syscall(__NR_sendmsg, -1, 0x20000600ul, 0x40000ul);
+ break;
+ case 3:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 4:
+ *(uint64_t*)0x20000280 = 0;
+ *(uint32_t*)0x20000288 = 0x2d3;
+ *(uint64_t*)0x20000290 = 0x20000240;
+ *(uint64_t*)0x20000240 = 0x200002c0;
+ memcpy(
+ (void*)0x200002c0,
+ "\x14\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00"
+ "\x00\x00\x0a\x20\x00\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00"
+ "\x00\x70\x00\x00\x00\x12\x0a\x01\x00\x00\x1f\x34\x01\x04\x00\x00\x00"
+ "\x00\x00\x00\x00\x04\x00\x04\x80\x09\x00\x02\x00\x73\x79\x7a\x30\x00"
+ "\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00"
+ "\x03\x40\x00\x00\x00\x00\x22\x00\x02\x00\xb7\x63\x12\xc4\x11\x0d\xd9"
+ "\xb1\x73\x79\xe7\x28\x14\x7a\xfe\x6a\xb9\xf3\x2a\xa9\xd1\x00\x04\x80"
+ "\x00\x00\x04\x00\x06\x14\x00\x04\x80\x09\x00\x01\x00\x59\x79\x7a\x30"
+ "\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x11\x00\x6d\x30\xa1\x6e\x90"
+ "\x01\x6c\x47\x8a\x50\x48\x3a\x73\x64\x5a\x6d\xc4\xb5\x34\x5d\x2c\x0d"
+ "\xb7\x4c\x9f\x89\x67\x8f\xbc\x9c\xc6\xfb\x9e\x8e\x31\xfa\xd7\xe7\x58"
+ "\x0e\x6a\xe4\x35\x8d\x8f\x95\xa2\x73\x5d\x57\xdc\x6e\x3a\xf5\xcf\x3e"
+ "\x09\xaa\x68\xb1\x91\xfe\xa4\x67\x66\xe9\xa1\xb3\xb4\xc9\xb0\x75\xf7"
+ "\x4c\x98\x1f\x80\x44\x53\x89\x8a\x0b\x8f\x9d\x08\x1e\xf6\x43\x7d\x40"
+ "\x51\xa3\x1e\xef\xf8\x78\x44\x21\xe4\x78\xa6\xe0\x4e\x0f\xb3\x69\xef"
+ "\x95\xf2\x89\xff\x35\xa2\x43\x34\xba\x0d\x5a\xc0\x37\x02\x8b\x66\x59"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 299);
+ *(uint64_t*)0x20000248 = 0xb8;
+ *(uint64_t*)0x20000298 = 1;
+ *(uint64_t*)0x200002a0 = 0;
+ *(uint64_t*)0x200002a8 = 0;
+ *(uint32_t*)0x200002b0 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000280ul, 0ul);
+ break;
+ case 5:
+ *(uint64_t*)0x20000180 = 0;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0x20000c00;
+ *(uint64_t*)0x20000c00 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x14;
+ *(uint16_t*)0x20000004 = 0x10;
+ *(uint16_t*)0x20000006 = 1;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 0;
+ *(uint16_t*)0x20000012 = htobe16(0xa);
+ *(uint32_t*)0x20000014 = 0x44;
+ *(uint8_t*)0x20000018 = 9;
+ *(uint8_t*)0x20000019 = 0xa;
+ *(uint16_t*)0x2000001a = 0xdfc9;
+ *(uint32_t*)0x2000001c = 0;
+ *(uint32_t*)0x20000020 = 0;
+ *(uint8_t*)0x20000024 = 0;
+ *(uint8_t*)0x20000025 = 0;
+ *(uint16_t*)0x20000026 = htobe16(0);
+ *(uint16_t*)0x20000028 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000002a, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000002b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000002b, 0, 7, 1);
+ *(uint32_t*)0x2000002c = htobe32(0x2b);
+ *(uint16_t*)0x20000030 = 9;
+ *(uint16_t*)0x20000032 = 1;
+ memcpy((void*)0x20000034, "syz0\000", 5);
+ *(uint16_t*)0x2000003c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000003e, 0xa, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000003f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000003f, 0, 7, 1);
+ *(uint32_t*)0x20000040 = htobe32(0);
+ *(uint16_t*)0x20000044 = 9;
+ *(uint16_t*)0x20000046 = 2;
+ memcpy((void*)0x20000048, "syz1\000", 5);
+ *(uint16_t*)0x20000050 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000052, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000053, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000053, 0, 7, 1);
+ *(uint32_t*)0x20000054 = htobe32(2);
+ *(uint32_t*)0x20000058 = 0x14;
+ *(uint16_t*)0x2000005c = 0x11;
+ *(uint16_t*)0x2000005e = 1;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint8_t*)0x20000068 = 0;
+ *(uint8_t*)0x20000069 = 0;
+ *(uint16_t*)0x2000006a = htobe16(0xa);
+ *(uint64_t*)0x20000c08 = 0x6c;
+ *(uint64_t*)0x20000198 = 1;
+ *(uint64_t*)0x200001a0 = 0;
+ *(uint64_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001b0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000180ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b2846c7751a664d14ed5bfde51972a0be01d59b5.c b/syzkaller-repros/linux/b2846c7751a664d14ed5bfde51972a0be01d59b5.c
new file mode 100644
index 0000000..64da182
--- /dev/null
+++ b/syzkaller-repros/linux/b2846c7751a664d14ed5bfde51972a0be01d59b5.c
@@ -0,0 +1,1010 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/usb/ch9.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(int sock, const char* name, const void* addr,
+ int addrsize, const void* mac, int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ netlink_attr(NDA_DST, addr, addrsize);
+ netlink_attr(NDA_LLADDR, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+#define SYZ_TUN_MAX_PACKET_SIZE 1000
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in_addr, sizeof(in_addr), &macaddr,
+ ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in6_addr, sizeof(in6_addr), &macaddr,
+ ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN);
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[SYZ_TUN_MAX_PACKET_SIZE];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+ setup_binfmt_misc();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_LOOP 1
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+#define SYZ_HAVE_CLOSE_FDS 1
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+void execute_one(void)
+{
+ *(uint8_t*)0x20000000 = 0x12;
+ *(uint8_t*)0x20000001 = 1;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint8_t*)0x20000004 = 0x65;
+ *(uint8_t*)0x20000005 = 0x99;
+ *(uint8_t*)0x20000006 = 0xc1;
+ *(uint8_t*)0x20000007 = 0;
+ *(uint16_t*)0x20000008 = 0x12d1;
+ *(uint16_t*)0x2000000a = 0xac23;
+ *(uint16_t*)0x2000000c = 0xe111;
+ *(uint8_t*)0x2000000e = 0;
+ *(uint8_t*)0x2000000f = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 1;
+ *(uint8_t*)0x20000012 = 9;
+ *(uint8_t*)0x20000013 = 2;
+ *(uint16_t*)0x20000014 = 0x12;
+ *(uint8_t*)0x20000016 = 1;
+ *(uint8_t*)0x20000017 = 0;
+ *(uint8_t*)0x20000018 = 0;
+ *(uint8_t*)0x20000019 = 0;
+ *(uint8_t*)0x2000001a = 0;
+ *(uint8_t*)0x2000001b = 9;
+ *(uint8_t*)0x2000001c = 4;
+ *(uint8_t*)0x2000001d = 0xfe;
+ *(uint8_t*)0x2000001e = 0;
+ *(uint8_t*)0x2000001f = 0;
+ *(uint8_t*)0x20000020 = -1;
+ *(uint8_t*)0x20000021 = 2;
+ *(uint8_t*)0x20000022 = 0x16;
+ *(uint8_t*)0x20000023 = 0;
+ syz_usb_connect(0, 0x24, 0x20000000, 0);
+ *(uint8_t*)0x20000040 = 0x12;
+ *(uint8_t*)0x20000041 = 1;
+ *(uint16_t*)0x20000042 = 0;
+ *(uint8_t*)0x20000044 = 5;
+ *(uint8_t*)0x20000045 = 0xa4;
+ *(uint8_t*)0x20000046 = 0xc0;
+ *(uint8_t*)0x20000047 = 8;
+ *(uint16_t*)0x20000048 = 0xc72;
+ *(uint16_t*)0x2000004a = 0x13;
+ *(uint16_t*)0x2000004c = 0x7216;
+ *(uint8_t*)0x2000004e = 5;
+ *(uint8_t*)0x2000004f = 0;
+ *(uint8_t*)0x20000050 = 5;
+ *(uint8_t*)0x20000051 = 1;
+ *(uint8_t*)0x20000052 = 9;
+ *(uint8_t*)0x20000053 = 2;
+ *(uint16_t*)0x20000054 = 0x26;
+ *(uint8_t*)0x20000056 = 1;
+ *(uint8_t*)0x20000057 = 0x6b;
+ *(uint8_t*)0x20000058 = 7;
+ *(uint8_t*)0x20000059 = 0x20;
+ *(uint8_t*)0x2000005a = 0;
+ *(uint8_t*)0x2000005b = 9;
+ *(uint8_t*)0x2000005c = 4;
+ *(uint8_t*)0x2000005d = 0xe0;
+ *(uint8_t*)0x2000005e = 0;
+ *(uint8_t*)0x2000005f = 2;
+ *(uint8_t*)0x20000060 = 0x38;
+ *(uint8_t*)0x20000061 = 0x22;
+ *(uint8_t*)0x20000062 = 0xfe;
+ *(uint8_t*)0x20000063 = 6;
+ *(uint8_t*)0x20000064 = 7;
+ *(uint8_t*)0x20000065 = 5;
+ *(uint8_t*)0x20000066 = 8;
+ *(uint8_t*)0x20000067 = 0xc;
+ *(uint16_t*)0x20000068 = 0;
+ *(uint8_t*)0x2000006a = 2;
+ *(uint8_t*)0x2000006b = 6;
+ *(uint8_t*)0x2000006c = 2;
+ *(uint8_t*)0x2000006d = 2;
+ *(uint8_t*)0x2000006e = 0x11;
+ *(uint8_t*)0x2000006f = 7;
+ *(uint8_t*)0x20000070 = 5;
+ *(uint8_t*)0x20000071 = 0;
+ *(uint8_t*)0x20000072 = 0;
+ *(uint16_t*)0x20000073 = 0;
+ *(uint8_t*)0x20000075 = 0;
+ *(uint8_t*)0x20000076 = 0;
+ *(uint8_t*)0x20000077 = 0;
+ syz_usb_connect(6, 0x38, 0x20000040, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ use_temporary_dir();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b304e48c105e40ff49f5da148009e29029e0431b.c b/syzkaller-repros/linux/b304e48c105e40ff49f5da148009e29029e0431b.c
new file mode 100644
index 0000000..c1c0e93
--- /dev/null
+++ b/syzkaller-repros/linux/b304e48c105e40ff49f5da148009e29029e0431b.c
@@ -0,0 +1,205 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0x20000100;
+ *(uint64_t*)0x20000100 = 0x20000180;
+ *(uint32_t*)0x20000180 = 0x64;
+ *(uint8_t*)0x20000184 = 2;
+ *(uint8_t*)0x20000185 = 6;
+ *(uint16_t*)0x20000186 = 0x101;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint32_t*)0x2000018c = 0;
+ *(uint8_t*)0x20000190 = 0;
+ *(uint8_t*)0x20000191 = 0;
+ *(uint16_t*)0x20000192 = htobe16(0);
+ *(uint16_t*)0x20000194 = 5;
+ *(uint16_t*)0x20000196 = 1;
+ *(uint8_t*)0x20000198 = 7;
+ *(uint16_t*)0x2000019c = 5;
+ *(uint16_t*)0x2000019e = 4;
+ *(uint8_t*)0x200001a0 = 0;
+ *(uint16_t*)0x200001a4 = 0x10;
+ *(uint16_t*)0x200001a6 = 3;
+ memcpy((void*)0x200001a8, "bitmap:port\000", 12);
+ *(uint16_t*)0x200001b4 = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x200001b6, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001b7, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001b7, 1, 7, 1);
+ *(uint16_t*)0x200001b8 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ba, 5, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001bb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001bb, 0, 7, 1);
+ *(uint16_t*)0x200001bc = htobe16(0);
+ *(uint16_t*)0x200001c0 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x200001c2, 4, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001c3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001c3, 0, 7, 1);
+ *(uint16_t*)0x200001c4 = htobe16(0);
+ *(uint16_t*)0x200001c8 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ca, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001cb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001cb, 0, 7, 1);
+ *(uint32_t*)0x200001cc = htobe32(3);
+ *(uint16_t*)0x200001d0 = 9;
+ *(uint16_t*)0x200001d2 = 2;
+ memcpy((void*)0x200001d4, "syz0\000", 5);
+ *(uint16_t*)0x200001dc = 5;
+ *(uint16_t*)0x200001de = 5;
+ *(uint8_t*)0x200001e0 = 0;
+ *(uint64_t*)0x20000108 = 0x64;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000140ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b482c6fe08771a40799a9f1493ed89eab15317df.c b/syzkaller-repros/linux/b482c6fe08771a40799a9f1493ed89eab15317df.c
new file mode 100644
index 0000000..7c495e4
--- /dev/null
+++ b/syzkaller-repros/linux/b482c6fe08771a40799a9f1493ed89eab15317df.c
@@ -0,0 +1,945 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0x20;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0x40;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint32_t*)0x200000b8 = 0;
+ *(uint32_t*)0x200000bc = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000040ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000100, "\xf3", 1);
+ syscall(__NR_ioctl, r[1], 0x4b61ul, 0x20000100ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b4898106f15c86708a41b4f8289636f891305544.c b/syzkaller-repros/linux/b4898106f15c86708a41b4f8289636f891305544.c
new file mode 100644
index 0000000..0000d65
--- /dev/null
+++ b/syzkaller-repros/linux/b4898106f15c86708a41b4f8289636f891305544.c
@@ -0,0 +1,353 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+
+ *(uint8_t*)0x20001000 = 0x12;
+ *(uint8_t*)0x20001001 = 1;
+ *(uint16_t*)0x20001002 = 0;
+ *(uint8_t*)0x20001004 = 0xb9;
+ *(uint8_t*)0x20001005 = 0x4b;
+ *(uint8_t*)0x20001006 = 0x96;
+ *(uint8_t*)0x20001007 = 0x40;
+ *(uint16_t*)0x20001008 = 0xccd;
+ *(uint16_t*)0x2000100a = 0x39;
+ *(uint16_t*)0x2000100c = 0xcf8e;
+ *(uint8_t*)0x2000100e = 0;
+ *(uint8_t*)0x2000100f = 0;
+ *(uint8_t*)0x20001010 = 0;
+ *(uint8_t*)0x20001011 = 1;
+ *(uint8_t*)0x20001012 = 9;
+ *(uint8_t*)0x20001013 = 2;
+ *(uint16_t*)0x20001014 = 0x24;
+ *(uint8_t*)0x20001016 = 1;
+ *(uint8_t*)0x20001017 = 0;
+ *(uint8_t*)0x20001018 = 0;
+ *(uint8_t*)0x20001019 = 0;
+ *(uint8_t*)0x2000101a = 0;
+ *(uint8_t*)0x2000101b = 9;
+ *(uint8_t*)0x2000101c = 4;
+ *(uint8_t*)0x2000101d = 0xbf;
+ *(uint8_t*)0x2000101e = 0;
+ *(uint8_t*)0x2000101f = 2;
+ *(uint8_t*)0x20001020 = 0xa0;
+ *(uint8_t*)0x20001021 = 0x6c;
+ *(uint8_t*)0x20001022 = 0x27;
+ *(uint8_t*)0x20001023 = 0;
+ *(uint8_t*)0x20001024 = 7;
+ *(uint8_t*)0x20001025 = 5;
+ *(uint8_t*)0x20001026 = 6;
+ *(uint8_t*)0x20001027 = 0;
+ *(uint16_t*)0x20001028 = 0;
+ *(uint8_t*)0x2000102a = 0;
+ *(uint8_t*)0x2000102b = 2;
+ *(uint8_t*)0x2000102c = 0;
+ *(uint8_t*)0x2000102d = 7;
+ *(uint8_t*)0x2000102e = 5;
+ *(uint8_t*)0x2000102f = 2;
+ *(uint8_t*)0x20001030 = 3;
+ *(uint16_t*)0x20001031 = 0;
+ *(uint8_t*)0x20001033 = 0x8d;
+ *(uint8_t*)0x20001034 = 0;
+ *(uint8_t*)0x20001035 = 0;
+ syz_usb_connect(7, 0x36, 0x20001000, 0);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b4d4d45523ff8bd6037cdda888b1f324e3bd790d.c b/syzkaller-repros/linux/b4d4d45523ff8bd6037cdda888b1f324e3bd790d.c
new file mode 100644
index 0000000..d7f6d09
--- /dev/null
+++ b/syzkaller-repros/linux/b4d4d45523ff8bd6037cdda888b1f324e3bd790d.c
@@ -0,0 +1,525 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0x0, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_creat, 0ul, 0ul);
+ syscall(__NR_write, -1, 0ul, 0xb18ffbffc48ec12ul);
+ syscall(__NR_setsockopt, -1, 1ul, 0x11ul, 0ul, 0ul);
+ syscall(__NR_keyctl, 0x16ul, 0, 0, 0, 0);
+ syscall(__NR_getgid);
+ syscall(__NR_ioctl, -1, 0x5423ul, 0ul);
+ syscall(__NR_splice, -1, 0ul, -1, 0ul, 0ul, 8ul);
+ syscall(__NR_gettid);
+ res = syscall(__NR_getgid);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_setfsgid, r[0]);
+ syscall(__NR_sendto, -1, 0ul, 0ul, 0ul, 0ul, 0ul);
+ syz_open_dev(0, 0xfffffffffffffeff, 0);
+ syscall(__NR_sendto, -1, 0ul, 0ul, 0x200007fful, 0ul, 0ul);
+ syscall(__NR_splice, -1, 0ul, -1, 0ul, 0ul, 8ul);
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0ul, 0ul);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_ioctl, r[1], 0x5423ul, 0ul);
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0ul, 0ul);
+ syscall(__NR_gettid);
+ syscall(__NR_setsockopt, -1, 1ul, 0x11ul, 0ul, 0ul);
+ syscall(__NR_socket, 2ul, 0ul, 0);
+ syscall(__NR_sendto, -1, 0ul, 0ul, 0ul, 0ul, 0ul);
+ syscall(__NR_fstat, -1, 0ul);
+ syscall(__NR_add_key, 0ul, 0ul, 0ul, 0ul, 0);
+ syscall(__NR_splice, -1, 0ul, -1, 0ul, 0ul, 0ul);
+ syscall(__NR_perf_event_open, 0ul, 0, 0ul, -1, 0ul);
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 2ul, 0ul);
+ NONFAILING(memcpy((void*)0x20000040, "/dev/ptmx\000", 10));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ NONFAILING(*(uint32_t*)0x200001c0 = 0x11);
+ inject_fault(6);
+ syscall(__NR_ioctl, r[2], 0x5423ul, 0x200001c0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b5d9f4bd1577a82194bb194ab17ff01022a39827.c b/syzkaller-repros/linux/b5d9f4bd1577a82194bb194ab17ff01022a39827.c
new file mode 100644
index 0000000..7be8351
--- /dev/null
+++ b/syzkaller-repros/linux/b5d9f4bd1577a82194bb194ab17ff01022a39827.c
@@ -0,0 +1,675 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 3; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000000, "/dev/tty1#\000", 11);
+ syz_open_dev(0x20000000, 0xe3, 0x800);
+ break;
+ case 1:
+ memcpy((void*)0x20000000, "/dev/tty1#\000", 11);
+ res = syz_open_dev(0x20000000, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ syscall(__NR_ioctl, r[0], 0x5608ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b641a2146b1768b13e6c37113f601f4a4ee5c639.c b/syzkaller-repros/linux/b641a2146b1768b13e6c37113f601f4a4ee5c639.c
new file mode 100644
index 0000000..79fcd4b
--- /dev/null
+++ b/syzkaller-repros/linux/b641a2146b1768b13e6c37113f601f4a4ee5c639.c
@@ -0,0 +1,210 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static long syz_init_net_socket(volatile long domain, volatile long type,
+ volatile long proto)
+{
+ return syscall(__NR_socket, domain, type, proto);
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ install_segv_handler();
+ use_temporary_dir();
+ intptr_t res = 0;
+ res = syz_init_net_socket(0x1a, 1, 0);
+ if (res != -1)
+ r[0] = res;
+ NONFAILING(*(uint16_t*)0x20000040 = 0x1a);
+ NONFAILING(*(uint16_t*)0x20000042 = 1);
+ NONFAILING(*(uint8_t*)0x20000044 = 0);
+ NONFAILING(*(uint8_t*)0x20000045 = 0);
+ NONFAILING(*(uint8_t*)0x20000046 = 0);
+ NONFAILING(*(uint8_t*)0x20000047 = 0);
+ NONFAILING(*(uint8_t*)0x20000048 = 0);
+ NONFAILING(*(uint8_t*)0x20000049 = 0);
+ NONFAILING(*(uint8_t*)0x2000004a = 0);
+ NONFAILING(*(uint8_t*)0x2000004b = 0);
+ NONFAILING(*(uint8_t*)0x2000004c = 0);
+ NONFAILING(*(uint8_t*)0x2000004d = 0);
+ syscall(__NR_bind, r[0], 0x20000040, 0x10);
+ NONFAILING(*(uint16_t*)0x20000100 = 0x1a);
+ NONFAILING(*(uint16_t*)0x20000102 = 0);
+ NONFAILING(*(uint8_t*)0x20000104 = 0);
+ NONFAILING(*(uint8_t*)0x20000105 = 0);
+ NONFAILING(*(uint8_t*)0x20000106 = 0);
+ NONFAILING(*(uint8_t*)0x20000107 = 0);
+ NONFAILING(*(uint8_t*)0x20000108 = 1);
+ NONFAILING(*(uint8_t*)0x20000109 = 0x80);
+ NONFAILING(*(uint8_t*)0x2000010a = 0xc2);
+ NONFAILING(*(uint8_t*)0x2000010b = 0);
+ NONFAILING(*(uint8_t*)0x2000010c = 0);
+ NONFAILING(*(uint8_t*)0x2000010d = 0);
+ syscall(__NR_connect, r[0], 0x20000100, 0x10);
+ check_leaks();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b6e19a81ffabd2d0ee90b113fbadcfde65588f93.c b/syzkaller-repros/linux/b6e19a81ffabd2d0ee90b113fbadcfde65588f93.c
new file mode 100644
index 0000000..b75eead
--- /dev/null
+++ b/syzkaller-repros/linux/b6e19a81ffabd2d0ee90b113fbadcfde65588f93.c
@@ -0,0 +1,235 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x200004c0;
+ *(uint32_t*)0x200004c0 = 0x7c;
+ *(uint8_t*)0x200004c4 = 2;
+ *(uint8_t*)0x200004c5 = 6;
+ *(uint16_t*)0x200004c6 = 1;
+ *(uint32_t*)0x200004c8 = 0;
+ *(uint32_t*)0x200004cc = 0;
+ *(uint8_t*)0x200004d0 = 0;
+ *(uint8_t*)0x200004d1 = 0;
+ *(uint16_t*)0x200004d2 = htobe16(0);
+ *(uint16_t*)0x200004d4 = 0xe;
+ *(uint16_t*)0x200004d6 = 3;
+ memcpy((void*)0x200004d8, "bitmap:ip\000", 10);
+ *(uint16_t*)0x200004e4 = 9;
+ *(uint16_t*)0x200004e6 = 2;
+ memcpy((void*)0x200004e8, "syz1\000", 5);
+ *(uint16_t*)0x200004f0 = 0x34;
+ STORE_BY_BITMASK(uint16_t, , 0x200004f2, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004f3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004f3, 1, 7, 1);
+ *(uint16_t*)0x200004f4 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200004f6, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004f7, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004f7, 1, 7, 1);
+ *(uint16_t*)0x200004f8 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200004fa, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004fb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004fb, 0, 7, 1);
+ *(uint32_t*)0x200004fc = htobe32(0x9effffff);
+ *(uint16_t*)0x20000500 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000502, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000503, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000503, 1, 7, 1);
+ *(uint16_t*)0x20000504 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000506, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000507, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000507, 0, 7, 1);
+ *(uint8_t*)0x20000508 = 0xac;
+ *(uint8_t*)0x20000509 = 0x1e;
+ *(uint8_t*)0x2000050a = 0;
+ *(uint8_t*)0x2000050b = 1;
+ *(uint16_t*)0x2000050c = 5;
+ *(uint16_t*)0x2000050e = 0x14;
+ *(uint8_t*)0x20000510 = 5;
+ *(uint16_t*)0x20000514 = 5;
+ *(uint16_t*)0x20000516 = 0x14;
+ *(uint8_t*)0x20000518 = 3;
+ *(uint16_t*)0x2000051c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000051e, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000051f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000051f, 0, 7, 1);
+ *(uint32_t*)0x20000520 = htobe32(0x18);
+ *(uint16_t*)0x20000524 = 5;
+ *(uint16_t*)0x20000526 = 1;
+ *(uint8_t*)0x20000528 = 7;
+ *(uint16_t*)0x2000052c = 5;
+ *(uint16_t*)0x2000052e = 4;
+ *(uint8_t*)0x20000530 = 0;
+ *(uint16_t*)0x20000534 = 5;
+ *(uint16_t*)0x20000536 = 5;
+ *(uint8_t*)0x20000538 = 2;
+ *(uint64_t*)0x200002c8 = 0x7c;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0x40000;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b701a1c2840d516fe41ed0bd76c4a0216061a4ef.c b/syzkaller-repros/linux/b701a1c2840d516fe41ed0bd76c4a0216061a4ef.c
new file mode 100644
index 0000000..561a0e8
--- /dev/null
+++ b/syzkaller-repros/linux/b701a1c2840d516fe41ed0bd76c4a0216061a4ef.c
@@ -0,0 +1,303 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ if (pthread_create(&th, &attr, fn, arg))
+ exit(1);
+ pthread_attr_destroy(&attr);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+}
+
+#define SYZ_HAVE_RESET_TEST 1
+static void reset_test()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ reset_test();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000140, "/dev/video#", 12);
+ res = syz_open_dev(0x20000140, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint32_t*)0x20000100 = 0;
+ *(uint32_t*)0x20000104 = 1;
+ *(uint32_t*)0x20000108 = 0;
+ *(uint32_t*)0x2000010c = 0;
+ *(uint32_t*)0x20000110 = 0;
+ syscall(__NR_ioctl, r[0], 0xc0585609, 0x20000100);
+ break;
+ case 2:
+ memcpy((void*)0x200000c0, "/dev/video#", 12);
+ res = syz_open_dev(0x200000c0, 0x8447, 2);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ syscall(__NR_read, r[1], 0x20000100, 0x249);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b73bb88d699a3274fc7d1fcd654b5cdf4a2c4ef1.c b/syzkaller-repros/linux/b73bb88d699a3274fc7d1fcd654b5cdf4a2c4ef1.c
new file mode 100644
index 0000000..8513af1
--- /dev/null
+++ b/syzkaller-repros/linux/b73bb88d699a3274fc7d1fcd654b5cdf4a2c4ef1.c
@@ -0,0 +1,613 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 7; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ NONFAILING(memcpy((void*)0x20000040, "/dev/watch_queue\000", 17));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000040ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_mmap, 0x20ff5000ul, 0x8000ul, 0ul, 0x13ul, r[0], 0ul);
+ break;
+ case 2:
+ syz_open_dev(0, 0x401, 0x24840);
+ break;
+ case 3:
+ NONFAILING(memcpy((void*)0x20000000, "/dev/hidraw#\000", 13));
+ syz_open_dev(0x20000000, 5, 0x80000);
+ break;
+ case 4:
+ res = syz_open_dev(0, 0, 0x201);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 5:
+ NONFAILING(memcpy((void*)0x20001200, "\000", 1));
+ syscall(__NR_write, r[1], 0x20001200ul, 0xffffff45ul);
+ break;
+ case 6:
+ syscall(__NR_ioctl, r[1], 0xc0404806ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/b7d5993be89a011ed89a6f4fb13bf0499ee236e7.c b/syzkaller-repros/linux/b7d5993be89a011ed89a6f4fb13bf0499ee236e7.c
new file mode 100644
index 0000000..6132272
--- /dev/null
+++ b/syzkaller-repros/linux/b7d5993be89a011ed89a6f4fb13bf0499ee236e7.c
@@ -0,0 +1,1104 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000180 = 6;
+ *(uint32_t*)0x20000184 = 4;
+ *(uint64_t*)0x20000188 = 0x20000200;
+ memcpy((void*)0x20000200,
+ "\x18\x02\x00\x00\x00\xec\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85"
+ "\x00\x00\x00\x2c\x00\x00\x00\x95\x00\x00\x00\x00\x00\x00\x00",
+ 32);
+ *(uint64_t*)0x20000190 = 0x200000c0;
+ memcpy((void*)0x200000c0, "GPL\000", 4);
+ *(uint32_t*)0x20000198 = 4;
+ *(uint32_t*)0x2000019c = 0x1000;
+ *(uint64_t*)0x200001a0 = 0x2062b000;
+ *(uint32_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001ac = 0;
+ *(uint8_t*)0x200001b0 = 0;
+ *(uint8_t*)0x200001b1 = 0;
+ *(uint8_t*)0x200001b2 = 0;
+ *(uint8_t*)0x200001b3 = 0;
+ *(uint8_t*)0x200001b4 = 0;
+ *(uint8_t*)0x200001b5 = 0;
+ *(uint8_t*)0x200001b6 = 0;
+ *(uint8_t*)0x200001b7 = 0;
+ *(uint8_t*)0x200001b8 = 0;
+ *(uint8_t*)0x200001b9 = 0;
+ *(uint8_t*)0x200001ba = 0;
+ *(uint8_t*)0x200001bb = 0;
+ *(uint8_t*)0x200001bc = 0;
+ *(uint8_t*)0x200001bd = 0;
+ *(uint8_t*)0x200001be = 0;
+ *(uint8_t*)0x200001bf = 0;
+ *(uint32_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c4 = 0;
+ *(uint32_t*)0x200001c8 = -1;
+ *(uint32_t*)0x200001cc = 8;
+ *(uint64_t*)0x200001d0 = 0;
+ *(uint32_t*)0x200001d8 = 0;
+ *(uint32_t*)0x200001dc = 0x10;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint32_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001ec = 0;
+ *(uint32_t*)0x200001f0 = -1;
+ res = syscall(__NR_bpf, 5ul, 0x20000180ul, 0x70ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0x7a;
+ *(uint64_t*)0x20000150 = 0x20000080;
+ *(uint64_t*)0x20000080 = 0x20000040;
+ memcpy((void*)0x20000040,
+ "\x34\x00\x00\x00\x10\x00\x01\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x1b\x00",
+ 20);
+ *(uint32_t*)0x20000054 = 0;
+ memcpy((void*)0x20000058,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x2b\x80\x08\x00\x01\x00",
+ 16);
+ *(uint32_t*)0x20000068 = r[1];
+ memcpy((void*)0x2000006c, "\x08\x00\x1b\x00\x00\x00\x00\x00", 8);
+ *(uint64_t*)0x20000088 = 0x34;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000140ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/bafbad01f8de79fea86449546cb55ea6123f7edc.c b/syzkaller-repros/linux/bafbad01f8de79fea86449546cb55ea6123f7edc.c
new file mode 100644
index 0000000..eccc8c9
--- /dev/null
+++ b/syzkaller-repros/linux/bafbad01f8de79fea86449546cb55ea6123f7edc.c
@@ -0,0 +1,432 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/capability.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_tun.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/if_arp.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+const int kFailStatus = 67;
+const int kRetryStatus = 69;
+
+__attribute__((noreturn)) static void doexit(int status)
+{
+ volatile unsigned i;
+ syscall(__NR_exit_group, status);
+ for (i = 0;; i++) {
+ }
+}
+
+__attribute__((noreturn)) static void fail(const char* msg, ...)
+{
+ int e = errno;
+ fflush(stdout);
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, " (errno %d)\n", e);
+ doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
+}
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* uctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ doexit(sig);
+ for (;;) {
+ }
+}
+
+static void install_segv_handler()
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void use_temporary_dir()
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ fail("failed to mkdtemp");
+ if (chmod(tmpdir, 0777))
+ fail("failed to chmod");
+ if (chdir(tmpdir))
+ fail("failed to chdir");
+}
+
+static void vsnprintf_check(char* str, size_t size, const char* format,
+ va_list args)
+{
+ int rv;
+
+ rv = vsnprintf(str, size, format, args);
+ if (rv < 0)
+ fail("tun: snprintf failed");
+ if ((size_t)rv >= size)
+ fail("tun: string '%s...' doesn't fit into buffer", str);
+}
+
+static void snprintf_check(char* str, size_t size, const char* format,
+ ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vsnprintf_check(str, size, format, args);
+ va_end(args);
+}
+
+#define COMMAND_MAX_LEN 128
+
+static void execute_command(const char* format, ...)
+{
+ va_list args;
+ char command[COMMAND_MAX_LEN];
+ int rv;
+
+ va_start(args, format);
+
+ vsnprintf_check(command, sizeof(command), format, args);
+ rv = system(command);
+ if (rv != 0)
+ fail("tun: command \"%s\" failed with code %d", &command[0], rv);
+
+ va_end(args);
+}
+
+static int tunfd = -1;
+
+#define SYZ_TUN_MAX_PACKET_SIZE 1000
+
+#define MAX_PIDS 32
+#define ADDR_MAX_LEN 32
+
+#define LOCAL_MAC "aa:aa:aa:aa:aa:%02hx"
+#define REMOTE_MAC "bb:bb:bb:bb:bb:%02hx"
+
+#define LOCAL_IPV4 "172.20.%d.170"
+#define REMOTE_IPV4 "172.20.%d.187"
+
+#define LOCAL_IPV6 "fe80::%02hxaa"
+#define REMOTE_IPV6 "fe80::%02hxbb"
+
+static void initialize_tun(uint64_t pid)
+{
+ if (pid >= MAX_PIDS)
+ fail("tun: no more than %d executors", MAX_PIDS);
+ int id = pid;
+
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1)
+ fail("tun: can't open /dev/net/tun");
+
+ char iface[IFNAMSIZ];
+ snprintf_check(iface, sizeof(iface), "syz%d", id);
+
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ fail("tun: ioctl(TUNSETIFF) failed");
+
+ char local_mac[ADDR_MAX_LEN];
+ snprintf_check(local_mac, sizeof(local_mac), LOCAL_MAC, id);
+ char remote_mac[ADDR_MAX_LEN];
+ snprintf_check(remote_mac, sizeof(remote_mac), REMOTE_MAC, id);
+
+ char local_ipv4[ADDR_MAX_LEN];
+ snprintf_check(local_ipv4, sizeof(local_ipv4), LOCAL_IPV4, id);
+ char remote_ipv4[ADDR_MAX_LEN];
+ snprintf_check(remote_ipv4, sizeof(remote_ipv4), REMOTE_IPV4, id);
+
+ char local_ipv6[ADDR_MAX_LEN];
+ snprintf_check(local_ipv6, sizeof(local_ipv6), LOCAL_IPV6, id);
+ char remote_ipv6[ADDR_MAX_LEN];
+ snprintf_check(remote_ipv6, sizeof(remote_ipv6), REMOTE_IPV6, id);
+
+ execute_command("sysctl -w net.ipv6.conf.%s.accept_dad=0", iface);
+
+ execute_command("sysctl -w net.ipv6.conf.%s.router_solicitations=0",
+ iface);
+
+ execute_command("ip link set dev %s address %s", iface, local_mac);
+ execute_command("ip addr add %s/24 dev %s", local_ipv4, iface);
+ execute_command("ip -6 addr add %s/120 dev %s", local_ipv6, iface);
+ execute_command("ip neigh add %s lladdr %s dev %s nud permanent",
+ remote_ipv4, remote_mac, iface);
+ execute_command("ip -6 neigh add %s lladdr %s dev %s nud permanent",
+ remote_ipv6, remote_mac, iface);
+ execute_command("ip link set dev %s up", iface);
+}
+
+static void setup_tun(uint64_t pid, bool enable_tun)
+{
+ if (enable_tun)
+ initialize_tun(pid);
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = 128 << 20;
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 8 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+
+ unshare(CLONE_NEWNS);
+ unshare(CLONE_NEWIPC);
+ unshare(CLONE_IO);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ close(fd);
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static int real_uid;
+static int real_gid;
+static int epid;
+static bool etun;
+__attribute__((aligned(64 << 10))) static char sandbox_stack[1 << 20];
+
+static int namespace_sandbox_proc(void* arg)
+{
+ sandbox_common();
+
+ write_file("/proc/self/setgroups", "deny");
+ if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid))
+ fail("write of /proc/self/uid_map failed");
+ if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid))
+ fail("write of /proc/self/gid_map failed");
+
+ setup_tun(epid, etun);
+
+ if (mkdir("./syz-tmp", 0777))
+ fail("mkdir(syz-tmp) failed");
+ if (mount("", "./syz-tmp", "tmpfs", 0, NULL))
+ fail("mount(tmpfs) failed");
+ if (mkdir("./syz-tmp/newroot", 0777))
+ fail("mkdir failed");
+ if (mkdir("./syz-tmp/newroot/dev", 0700))
+ fail("mkdir failed");
+ if (mount("/dev", "./syz-tmp/newroot/dev", NULL,
+ MS_BIND | MS_REC | MS_PRIVATE, NULL))
+ fail("mount(dev) failed");
+ if (mkdir("./syz-tmp/newroot/proc", 0700))
+ fail("mkdir failed");
+ if (mount(NULL, "./syz-tmp/newroot/proc", "proc", 0, NULL))
+ fail("mount(proc) failed");
+ if (mkdir("./syz-tmp/pivot", 0777))
+ fail("mkdir failed");
+ if (syscall(SYS_pivot_root, "./syz-tmp", "./syz-tmp/pivot")) {
+ if (chdir("./syz-tmp"))
+ fail("chdir failed");
+ } else {
+ if (chdir("/"))
+ fail("chdir failed");
+ if (umount2("./pivot", MNT_DETACH))
+ fail("umount failed");
+ }
+ if (chroot("./newroot"))
+ fail("chroot failed");
+ if (chdir("/"))
+ fail("chdir failed");
+
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ fail("capget failed");
+ cap_data[0].effective &= ~(1 << CAP_SYS_PTRACE);
+ cap_data[0].permitted &= ~(1 << CAP_SYS_PTRACE);
+ cap_data[0].inheritable &= ~(1 << CAP_SYS_PTRACE);
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ fail("capset failed");
+
+ loop();
+ doexit(1);
+}
+
+static int do_sandbox_namespace(int executor_pid, bool enable_tun)
+{
+ real_uid = getuid();
+ real_gid = getgid();
+ epid = executor_pid;
+ etun = enable_tun;
+ mprotect(sandbox_stack, 4096, PROT_NONE);
+ return clone(
+ namespace_sandbox_proc,
+ &sandbox_stack[sizeof(sandbox_stack) - 64],
+ CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNET, NULL);
+}
+
+long r[28];
+void* thr(void* arg)
+{
+ switch ((long)arg) {
+ case 0:
+ r[0] = syscall(__NR_mmap, 0x20000000ul, 0xfff000ul, 0x3ul, 0x32ul,
+ 0xfffffffffffffffful, 0x0ul);
+ break;
+ case 1:
+ r[1] =
+ syscall(__NR_socketpair, 0x2ul, 0x4ul, 0x7ffful, 0x20000ff8ul);
+ break;
+ case 2:
+ NONFAILING(*(uint32_t*)0x2019bfe4 = (uint32_t)0x1);
+ NONFAILING(*(uint32_t*)0x2019bfe8 = (uint32_t)0x1);
+ NONFAILING(*(uint32_t*)0x2019bfec = (uint32_t)0x9b);
+ NONFAILING(*(uint32_t*)0x2019bff0 = (uint32_t)0x6);
+ NONFAILING(*(uint32_t*)0x2019bff4 = (uint32_t)0x4);
+ NONFAILING(*(uint32_t*)0x2019bff8 = (uint32_t)0x0);
+ NONFAILING(*(uint32_t*)0x2019bffc = (uint32_t)0xfffffffffffffe01);
+ r[9] = syscall(__NR_bpf, 0x0ul, 0x2019bfe4ul, 0x1cul);
+ break;
+ case 3:
+ NONFAILING(*(uint32_t*)0x2003bfe0 = (uint32_t)0xffffffffffffffff);
+ NONFAILING(*(uint64_t*)0x2003bfe8 = (uint64_t)0x20714fff);
+ NONFAILING(*(uint64_t*)0x2003bff0 = (uint64_t)0x20037fff);
+ NONFAILING(*(uint64_t*)0x2003bff8 = (uint64_t)0x0);
+ NONFAILING(memcpy((void*)0x20037fff, "\x05", 1));
+ r[15] = syscall(__NR_bpf, 0x2ul, 0x2003bfe0ul, 0x20ul);
+ break;
+ case 4:
+ NONFAILING(*(uint32_t*)0x20047000 = (uint32_t)0xa);
+ r[17] = syscall(__NR_accept, 0xfffffffffffffffful, 0x20f51ff6ul,
+ 0x20047000ul);
+ break;
+ case 5:
+ NONFAILING(*(uint64_t*)0x20062000 = (uint64_t)0xac5f);
+ NONFAILING(*(uint64_t*)0x20062008 = (uint64_t)0x0);
+ NONFAILING(*(uint64_t*)0x20062010 = (uint64_t)0x10000);
+ NONFAILING(*(uint64_t*)0x20062018 = (uint64_t)0xb9c);
+ r[22] = syscall(__NR_ioctl, r[9], 0xc0206434ul, 0x20062000ul);
+ break;
+ case 6:
+ NONFAILING(*(uint64_t*)0x20ab9000 = (uint64_t)0x2);
+ NONFAILING(*(uint64_t*)0x20ab9008 = (uint64_t)0x0);
+ r[25] = syscall(__NR_ioctl, 0xfffffffffffffffful, 0x4010640dul,
+ 0x20ab9000ul);
+ break;
+ case 7:
+ NONFAILING(*(uint32_t*)0x20000000 = (uint32_t)0x14);
+ r[27] = syscall(__NR_getsockopt, 0xfffffffffffffffful, 0x29ul,
+ 0x14ul, 0x20687fecul, 0x20000000ul);
+ break;
+ }
+ return 0;
+}
+
+void loop()
+{
+ long i;
+ pthread_t th[16];
+
+ memset(r, -1, sizeof(r));
+ for (i = 0; i < 8; i++) {
+ pthread_create(&th[i], 0, thr, (void*)i);
+ usleep(rand() % 10000);
+ }
+ usleep(rand() % 100000);
+}
+
+int main()
+{
+ install_segv_handler();
+ use_temporary_dir();
+ int pid = do_sandbox_namespace(0, true);
+ int status = 0;
+ while (waitpid(pid, &status, __WALL) != pid) {
+ }
+ return 0;
+}
diff --git a/syzkaller-repros/linux/bbce98d65a84c401f0ba39d002f01d47f32492af.c b/syzkaller-repros/linux/bbce98d65a84c401f0ba39d002f01d47f32492af.c
new file mode 100644
index 0000000..34ad9a9
--- /dev/null
+++ b/syzkaller-repros/linux/bbce98d65a84c401f0ba39d002f01d47f32492af.c
@@ -0,0 +1,316 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0x20;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 1;
+ *(uint32_t*)0x20000094 = 0x60;
+ *(uint32_t*)0x20000098 = 0xb9;
+ *(uint32_t*)0x2000009c = 0x10001;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 7;
+ *(uint32_t*)0x200000ac = 0x800;
+ *(uint32_t*)0x200000b0 = 1;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint32_t*)0x200000b8 = 0xae;
+ *(uint32_t*)0x200000bc = 0xffff;
+ *(uint32_t*)0x200000c0 = 0x21;
+ *(uint32_t*)0x200000c4 = 0x100;
+ *(uint32_t*)0x200000c8 = 2;
+ *(uint32_t*)0x200000cc = 3;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000040ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/bcda6447d0e4d143d651f4de1db156bde861a3b9.c b/syzkaller-repros/linux/bcda6447d0e4d143d651f4de1db156bde861a3b9.c
new file mode 100644
index 0000000..f79483b
--- /dev/null
+++ b/syzkaller-repros/linux/bcda6447d0e4d143d651f4de1db156bde861a3b9.c
@@ -0,0 +1,1346 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ exit(1);
+ }
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[5] = {0xffffffffffffffff, 0xffffffffffffffff, 0x0,
+ 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x200000c0, "team0\000\000\000\000\000\000\000\000\000\000\000",
+ 16);
+ *(uint32_t*)0x200000d0 = 0;
+ res = syscall(__NR_ioctl, r[1], 0x8933ul, 0x200000c0ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x200000d0;
+ *(uint64_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint64_t*)0x20000010 = 0x20000100;
+ *(uint64_t*)0x20000100 = 0x200001c0;
+ *(uint32_t*)0x200001c0 = 0x58;
+ *(uint16_t*)0x200001c4 = 0x10;
+ *(uint16_t*)0x200001c6 = 0x401;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint32_t*)0x200001cc = 0;
+ *(uint8_t*)0x200001d0 = 0;
+ *(uint8_t*)0x200001d1 = 0;
+ *(uint16_t*)0x200001d2 = 0;
+ *(uint32_t*)0x200001d4 = 0;
+ *(uint32_t*)0x200001d8 = 0;
+ *(uint32_t*)0x200001dc = 0;
+ *(uint16_t*)0x200001e0 = 0x30;
+ STORE_BY_BITMASK(uint16_t, , 0x200001e2, 0x12, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001e3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001e3, 1, 7, 1);
+ *(uint16_t*)0x200001e4 = 8;
+ *(uint16_t*)0x200001e6 = 1;
+ memcpy((void*)0x200001e8, "sit\000", 4);
+ *(uint16_t*)0x200001ec = 0x24;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ee, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001ef, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001ef, 1, 7, 1);
+ *(uint16_t*)0x200001f0 = 5;
+ *(uint16_t*)0x200001f2 = 0xa;
+ *(uint8_t*)0x200001f4 = 1;
+ *(uint16_t*)0x200001f8 = 8;
+ *(uint16_t*)0x200001fa = 2;
+ *(uint8_t*)0x200001fc = 0xac;
+ *(uint8_t*)0x200001fd = 0x14;
+ *(uint8_t*)0x200001fe = 0x14;
+ *(uint8_t*)0x200001ff = 0xaa;
+ *(uint16_t*)0x20000200 = 6;
+ *(uint16_t*)0x20000202 = 0xd;
+ *(uint16_t*)0x20000204 = 4;
+ *(uint16_t*)0x20000208 = 6;
+ *(uint16_t*)0x2000020a = 0x12;
+ *(uint16_t*)0x2000020c = htobe16(0x4e23);
+ *(uint16_t*)0x20000210 = 8;
+ *(uint16_t*)0x20000212 = 0xa;
+ *(uint32_t*)0x20000214 = r[2];
+ *(uint64_t*)0x20000108 = 0x58;
+ *(uint64_t*)0x20000018 = 1;
+ *(uint64_t*)0x20000020 = 0;
+ *(uint64_t*)0x20000028 = 0;
+ *(uint32_t*)0x20000030 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000000ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[3] = res;
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0x20000200;
+ *(uint64_t*)0x20000200 = 0x200000c0;
+ memcpy((void*)0x200000c0,
+ "\x68\x00\x00\x00\x10\x00\x01\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00",
+ 20);
+ *(uint32_t*)0x200000d4 = 0;
+ memcpy((void*)0x200000d8,
+ "\x00\x00\x00\x00\x04\x00\x00\x00\x14\x00\x1a\x80\x10\x00\x02\x80\x0c"
+ "\x00\x01\x80\x08\x00\x04\x00\x00\x00\x00\x00\x08\x00\x1b\x00\x00\x00"
+ "\x00\x00\x08\x00\x29\x00\x00\x00\x00\x00\x14\x00\x14\x00\x62\x6f\x6e"
+ "\x64\x5f\x73\x6c\x61\x76\x65\x5f\x30\x00\x00\x00\x00\x08\x00\x0a\x00",
+ 68);
+ *(uint32_t*)0x2000011c = 0;
+ memcpy((void*)0x20000120, "\000\000\000\000\000\000\000\000", 8);
+ *(uint64_t*)0x20000208 = 0x68;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmsg, r[3], 0x20000140ul, 0x84ul);
+ res = syscall(__NR_socket, 0x10ul, 2ul, 0ul);
+ if (res != -1)
+ r[4] = res;
+ *(uint64_t*)0x20001640 = 0;
+ *(uint32_t*)0x20001648 = 0;
+ *(uint64_t*)0x20001650 = 0x20000140;
+ *(uint64_t*)0x20000140 = 0x20001600;
+ memcpy((void*)0x20001600,
+ "\x2e\x00\x00\x00\x10\x00\x81\x88\x04\x0f\x80\xec\xdb\x4c\xb9\xcc\xa7"
+ "\x48\x0e\xf4\x3c\x00\x00\x00\xe3\xbd\x6e\xfb\x44\x00\x09\x00\x0e\x00"
+ "\x0a\x00\x10\x00\x00\x00\x00\x80\x00\x00\x12\x01",
+ 46);
+ *(uint64_t*)0x20000148 = 0x2e;
+ *(uint64_t*)0x20001658 = 1;
+ *(uint64_t*)0x20001660 = 0;
+ *(uint64_t*)0x20001668 = 0;
+ *(uint32_t*)0x20001670 = 0;
+ syscall(__NR_sendmsg, r[4], 0x20001640ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/bd080858553377ac37175467b7a5dc01e9f499a5.c b/syzkaller-repros/linux/bd080858553377ac37175467b7a5dc01e9f499a5.c
new file mode 100644
index 0000000..e0a35f7
--- /dev/null
+++ b/syzkaller-repros/linux/bd080858553377ac37175467b7a5dc01e9f499a5.c
@@ -0,0 +1,92 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ long res = 0;
+ memcpy((void*)0x20000040, "/dev/video#", 12);
+ res = syz_open_dev(0x20000040, 0x6287, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000100 = 3;
+ *(uint32_t*)0x20000108 = 0;
+ *(uint32_t*)0x2000010c = 0;
+ *(uint32_t*)0x20000110 = 0;
+ *(uint32_t*)0x20000114 = 0;
+ *(uint32_t*)0x20000118 = 0;
+ *(uint32_t*)0x2000011c = 0;
+ *(uint64_t*)0x20000120 = 0x20000200;
+ *(uint32_t*)0x20000200 = 0xca;
+ *(uint32_t*)0x20000204 = 0;
+ *(uint32_t*)0x20000208 = 0;
+ *(uint32_t*)0x2000020c = 0;
+ *(uint64_t*)0x20000210 = 0;
+ *(uint32_t*)0x20000128 = 2;
+ *(uint64_t*)0x20000130 = 0x20000240;
+ *(uint8_t*)0x20000138 = 0;
+ syscall(__NR_ioctl, r[0], 0xc0d05605, 0x20000100);
+ memcpy((void*)0x20000040, "/dev/video#", 12);
+ res = syz_open_dev(0x20000040, 0x107fff, 0);
+ if (res != -1)
+ r[1] = res;
+ *(uint32_t*)0x20000240 = 2;
+ syscall(__NR_ioctl, r[1], 0xc0045627, 0x20000240);
+ *(uint32_t*)0x200000c0 = 3;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ *(uint64_t*)0x200000e0 = 0x20000080;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint64_t*)0x20000090 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint64_t*)0x20000010 = 0;
+ *(uint32_t*)0x200000e8 = 0;
+ *(uint64_t*)0x200000f0 = 0x200000c0;
+ *(uint8_t*)0x200000f8 = 0;
+ syscall(__NR_ioctl, r[1], 0xc0d05604, 0x200000c0);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/bddc7437dcb91ae53a0fd9672468ccd1152b1b4b.c b/syzkaller-repros/linux/bddc7437dcb91ae53a0fd9672468ccd1152b1b4b.c
new file mode 100644
index 0000000..49f537b
--- /dev/null
+++ b/syzkaller-repros/linux/bddc7437dcb91ae53a0fd9672468ccd1152b1b4b.c
@@ -0,0 +1,58 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20003e00 = 0;
+ *(uint32_t*)0x20003e08 = 0;
+ *(uint64_t*)0x20003e10 = 0x20003dc0;
+ *(uint64_t*)0x20003dc0 = 0x20000000;
+ memcpy(
+ (void*)0x20000000,
+ "\x14\x00\x00\x00\x10\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x0a\x20\x00\x00\x00\x00\x0a\x05\x14\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x01\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x6c\x00"
+ "\x00\x00\x16\x0a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x02\x00"
+ "\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x09\x00\x02\x00\x73\x79"
+ "\x7a\x32\x00\x00\x00\x00\x40\x00\x03\x80\x2c\x00\x03\x80\x14\x00\x01\x00"
+ "\x6c\x6f\x00\x00\x00\xfa\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x6d\x8c"
+ "\x02\x00\x73\x69\x74\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x08\x00\x02\x40\x00\x00\x00\x00\x08\x00\x01\x40\x00\x00\x00\x00\x7e\xff"
+ "\xff\xff\x11\x00\x01\x00\x00\x00\x0a\x02\x74\xc9\x8a\x01\x84\x6b\x90\xfb"
+ "\x08\xca\xad\x26\x13\x4e\x71\xfb\xa1\xff\xf7\xc8\x1c\x36\xc9\x74\x8c\x9e"
+ "\x51\xed\x67\x84\x09\xb2\x4e\x05\xd3\x12\x01\x96\xd4\x18\xfb\x02\xe7\xde"
+ "\x46\xab\x48\x62\x57\x80\xc2\xf3\x8e\x0e\x56\xd1\xc8\x88\xbb\xaa\x8c\xd8"
+ "\x1e\x39\xd4\xdf\xb0\x2a\x2a\x9e\x16\x2b\x71\x76\xca\xc4\xff\x45\xe0\x27"
+ "\xec\x73\xdd\xb1\x76\xd2\x7c\x93\x63\xaa\xb2\x76\x22\xc7\x82\x58\x70\x2a"
+ "\xcf\x7e\x80\x85\x14\x12\x5e\x11\xc1\x08\x5a\xef\xb3\x67\x71\xf2\x2e\x74"
+ "\x9d\x73\x3d\x95\x9a\x4b\x2d\xb1\x38\x49\x99\x9e\x24\xa8\xe0\x61\x1c\xd9"
+ "\xd6\xdc\xab\x75\x55\x20\xbc\xbc\x66\xbd\x47\x0b\x68\xe7\x97\xe4\x5b\x24"
+ "\x17\x30\xdc\x1a\x1c\x56\xbc\x40\xf1\x6a\xce\x8e\x6e\x8d\xa7\xcc\x46\x92"
+ "\xa3\xc9\xe2\xfa\x28\xc3\x75\xe9\xde\x3f\xe0\x89\x00\x84\x44\x4c\x61\xb6"
+ "\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 370);
+ *(uint64_t*)0x20003dc8 = 0xb4;
+ *(uint64_t*)0x20003e18 = 1;
+ *(uint64_t*)0x20003e20 = 0;
+ *(uint64_t*)0x20003e28 = 0;
+ *(uint32_t*)0x20003e30 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20003e00ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/be160e6f498300a335023b6b0e33fa4a0c9f2822.c b/syzkaller-repros/linux/be160e6f498300a335023b6b0e33fa4a0c9f2822.c
new file mode 100644
index 0000000..962af95
--- /dev/null
+++ b/syzkaller-repros/linux/be160e6f498300a335023b6b0e33fa4a0c9f2822.c
@@ -0,0 +1,283 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10, 3, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint64_t*)0x20000250 = 0x20000200;
+ *(uint64_t*)0x20000200 = 0x20000800;
+ *(uint32_t*)0x20000800 = 0x40;
+ *(uint16_t*)0x20000804 = 0x10;
+ *(uint16_t*)0x20000806 = 0xff1f;
+ *(uint32_t*)0x20000808 = 0;
+ *(uint32_t*)0x2000080c = 0;
+ *(uint8_t*)0x20000810 = 0;
+ *(uint8_t*)0x20000811 = 0;
+ *(uint16_t*)0x20000812 = 0;
+ *(uint32_t*)0x20000814 = 0;
+ *(uint32_t*)0x20000818 = 0;
+ *(uint32_t*)0x2000081c = 0;
+ *(uint16_t*)0x20000820 = 0x14;
+ *(uint16_t*)0x20000822 = 0x12;
+ *(uint16_t*)0x20000824 = 0xc;
+ *(uint16_t*)0x20000826 = 1;
+ memcpy((void*)0x20000828, "bridge\000", 7);
+ *(uint16_t*)0x20000830 = 4;
+ *(uint16_t*)0x20000832 = 2;
+ *(uint16_t*)0x20000834 = 0xa;
+ *(uint16_t*)0x20000836 = 1;
+ *(uint8_t*)0x20000838 = 0xaa;
+ *(uint8_t*)0x20000839 = 0xaa;
+ *(uint8_t*)0x2000083a = 0xaa;
+ *(uint8_t*)0x2000083b = 0xaa;
+ *(uint8_t*)0x2000083c = 0xaa;
+ *(uint8_t*)0x2000083d = 0;
+ *(uint64_t*)0x20000208 = 0x40;
+ *(uint64_t*)0x20000258 = 1;
+ *(uint64_t*)0x20000260 = 0;
+ *(uint64_t*)0x20000268 = 0;
+ *(uint32_t*)0x20000270 = 0;
+ inject_fault(20);
+ syscall(__NR_sendmsg, r[0], 0x20000240, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/bebad04768179c04b412f52d590e74b7200d383f.c b/syzkaller-repros/linux/bebad04768179c04b412f52d590e74b7200d383f.c
new file mode 100644
index 0000000..9211189
--- /dev/null
+++ b/syzkaller-repros/linux/bebad04768179c04b412f52d590e74b7200d383f.c
@@ -0,0 +1,678 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 10; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000000, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0x20;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0x40;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint32_t*)0x200000b8 = 0;
+ *(uint32_t*)0x200000bc = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000040ul);
+ break;
+ case 2:
+ res = syz_open_dev(0xc, 4, 3);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ *(uint8_t*)0x20000100 = 0x48;
+ memcpy(
+ (void*)0x20000101,
+ "\x18\x4d\xb8\x44\x1f\x6c\x80\x8e\x05\xee\x0a\x7c\xfe\x77\xc2\xc8\xf6"
+ "\x3c\x69\x38\x3a\x50\x09\xe7\xa7\xbb\x04\x9a\xf1\x05\x76\xbf\x8c\xfe"
+ "\x7a\xbe\x87\x79\x4a\x2b\xc7\xca\x77\xba\x9d\xce\x45\x76\xc3\x30\x6f"
+ "\xb8\x0b\xb4\x09\xe9\x3b\x72\x4e\xd9\xdd\x53\x08\x49\xbc\xd2\xe4\xdc"
+ "\x1e\x53\xbb\x0d\xc6\xd6\xc3\x28\x1d\x7e\x2e\xc3\x54\x4a\x72\x9b\xe0"
+ "\x30\x37\xc6\xc3\xa0\xe1\x4a\x4d\xb3\xb2\x66\x95\xf2\x31\xbf\x00\x45"
+ "\x4d\xfd\x58\xfb\x8f\x46\x21\x6a\xdc\x2c\x97\x01\x51\x0d\x7d\x3f\x93"
+ "\x39\x8c\x23\x50\xf8\x14\xa4\x9d\xc0\x91\xf4\x1d\xc6\x5c\xec\x5e\x6a"
+ "\x49\x0e\x8a\x0b\x86\xfa\x9d\x28\xcc\xef\xa2\xb8\x2b\xb1\x44\x87\xef"
+ "\xc6\xe0\x97\xc1\x82\x4a\x10\x28\xcc\x7d\x3d\x93\x37\x23\x36\x81\xbe"
+ "\x17\x33\x5f\x2e\x7e\x00\xeb\x53\x85\xcf\xea\xdd\x2e\x42\x4f\xf2\x2e"
+ "\xa9\xa0\xd1\xa1\x8e\xa8\xb8\x08\x9f\x73\x4a\x77\x42\x94\x8c\x40\xea"
+ "\xfe\x3d\xf4\xa4\x36\x19\x44\x96\xc8\x89\x43\x7d\xf5\x40\x3a\x67\x78"
+ "\xdc\x81\x14\x3a\x81\x43\x65\x65\x33\xc0\x74\xc1\x37\x06\x8d\xd9\x23"
+ "\x41\x93\xf6\x94\x6b\x67\x5a\xc6\x4e\xf2\xec\xc3\x26\x07\xdb\xc1\x1d"
+ "\xb2\x3f\xc4\x07\x35\xea\xdd\xe3\xe0\x5b\xc2\x94\x28\x3c\xcd\x07\x29"
+ "\xab\x18\xb8\xa7\x94\x37\xe6\x6b\x8c\x57\x4e\x46\xed\x5d\xe9\xba\x3e"
+ "\x85\xf7\x0f\x4e\x9e\x5f\xd4\x6f\xfe\xef\x65\xa1\xef\xeb\x63\x9f\x3b"
+ "\xa4\x29\xec\xaa\x41\x96\xef\xdb\xb3\xda\xf4\xc9\xd4\xaa\x77\x96\x2a"
+ "\x2b\x76\x20\xc1\x25\x0d\x2b\x43\x73\x0a\x9e\xd0\x1e\xcf\xf0\x72\x6e"
+ "\x6a\x32\x1b\x55\x62\x34\xb7\xea\xa5\xd1\x01\x14\xfa\xe4\x49\x74\x17"
+ "\x0e\x56\x3c\x18\xb9\x3e\xdd\xbe\x14\xcf\x63\x7d\xc3\xdc\xfb\x9e\xe6"
+ "\x87\xb5\xe0\xc6\xd6\x1f\x41\x3b\x33\x0d\x2e\x46\xdc\xa3\x4e\xf4\x8a"
+ "\x58\x43\xc2\x6c\xcc\xca\x9f\xe9\xcc\x28\xef\x89\xd2\x79\x47\x7e\x94"
+ "\x0a\x6e\x7c\xae\xd3\xb8\x8f\x43\xdb\x29\xb6\x5e\x99\x14\x59\xf9\x7e"
+ "\xad\x58\xa1\xa0\x00\x9e\xf6\x6d\xee\xd0\xe9\xff\x88\xf9\x2f\x4e\xc4"
+ "\xc7\x1d\xd0\xec\x3b\xfb\xb0\x08\x28\xfc\x71\x5c\x49\x1e\xde\xdb\x34"
+ "\x4d\xe3\x87\x51\xc7\x17\x3c\x8f\x84\xab\x5e\x79\x5e\x8c\x55\xde\x72"
+ "\x91\x1c\xca\x9a\x40\x27\x9b\x53\x33\xfb\x01\x56\x34\xa8\x3b\x22\xed"
+ "\x99\x8f\x45\xbd\x9f\x7b\x8d\x92\x8b\x55\x0b\xd9\x96\x97\x6c\x08\xb7"
+ "\x34\xb9",
+ 512);
+ syscall(__NR_ioctl, r[1], 0x4b48ul, 0x20000100ul);
+ break;
+ case 4:
+ syz_open_dev(0xc, 4, 3);
+ break;
+ case 5:
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 6:
+ syscall(__NR_ioctl, r[2], 0x4b69ul, 0ul);
+ break;
+ case 7:
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 8:
+ syscall(__NR_ioctl, r[3], 0x4b69ul, 0ul);
+ break;
+ case 9:
+ *(uint8_t*)0x20000340 = 2;
+ *(uint8_t*)0x20000341 = 5;
+ *(uint8_t*)0x20000342 = 6;
+ *(uint8_t*)0x20000343 = 8;
+ *(uint8_t*)0x20000344 = 0;
+ *(uint8_t*)0x20000345 = 0;
+ *(uint8_t*)0x20000346 = 0;
+ *(uint8_t*)0x20000347 = 0;
+ memcpy((void*)0x20000348,
+ "\x20\xbf\x1c\xe8\x4f\x83\x5f\x32\x5b\x0e\x42\x20\xcb\x13\xab\x7a",
+ 16);
+ syscall(__NR_ioctl, r[3], 0x800c6613ul, 0x20000340ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/bf3a6f60ba6ab6a233284f7a1fd52eadacf26bb4.c b/syzkaller-repros/linux/bf3a6f60ba6ab6a233284f7a1fd52eadacf26bb4.c
new file mode 100644
index 0000000..25931d5
--- /dev/null
+++ b/syzkaller-repros/linux/bf3a6f60ba6ab6a233284f7a1fd52eadacf26bb4.c
@@ -0,0 +1,578 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+ struct usb_device_descriptor* dev;
+ struct usb_config_descriptor* config;
+ unsigned config_length;
+ struct usb_interface_descriptor* iface;
+ struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+ unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+ struct usb_device_index* index)
+{
+ if (length <
+ sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+ return false;
+ index->dev = (struct usb_device_descriptor*)buffer;
+ index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+ index->config_length = length - sizeof(*index->dev);
+ index->iface =
+ (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+ sizeof(*index->config));
+ index->eps_num = 0;
+ size_t offset = 0;
+ while (true) {
+ if (offset == length)
+ break;
+ if (offset + 1 < length)
+ break;
+ uint8_t length = buffer[offset];
+ uint8_t type = buffer[offset + 1];
+ if (type == USB_DT_ENDPOINT) {
+ index->eps[index->eps_num] =
+ (struct usb_endpoint_descriptor*)(buffer + offset);
+ index->eps_num++;
+ }
+ if (index->eps_num == USB_MAX_EP_NUM)
+ break;
+ offset += length;
+ }
+ return true;
+}
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char* driver_name;
+ const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+ return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+ const char* device)
+{
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = driver;
+ arg.device_name = device;
+ return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+ return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_ep_io_data {
+ struct usb_fuzzer_ep_io inner;
+ char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+ uint32_t len;
+ char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+ uint32_t qual_len;
+ char* qual;
+ uint32_t bos_len;
+ char* bos;
+ uint32_t strs_len;
+ struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+ volatile long a2, volatile long a3)
+{
+ int64_t speed = a0;
+ int64_t dev_len = a1;
+ char* dev = (char*)a2;
+ struct vusb_connect_descriptors* conn_descs =
+ (struct vusb_connect_descriptors*)a3;
+ if (!dev)
+ return -1;
+ struct usb_device_index index;
+ memset(&index, 0, sizeof(index));
+ int rv = parse_usb_descriptor(dev, dev_len, &index);
+ if (!rv)
+ return -1;
+ int fd = usb_fuzzer_open();
+ if (fd < 0)
+ return -1;
+ char device[32];
+ sprintf(&device[0], "dummy_udc.%llu", procid);
+ rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_run(fd);
+ if (rv < 0)
+ return -1;
+ bool done = false;
+ while (!done) {
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ unsigned ep;
+ uint8_t str_idx;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ response_data = (char*)index.dev;
+ response_length = sizeof(*index.dev);
+ goto reply;
+ case USB_DT_CONFIG:
+ response_data = (char*)index.config;
+ response_length = index.config_length;
+ goto reply;
+ case USB_DT_STRING:
+ str_idx = (uint8_t)event.ctrl.wValue;
+ if (str_idx >= conn_descs->strs_len)
+ goto reply;
+ response_data = conn_descs->strs[str_idx].str;
+ response_length = conn_descs->strs[str_idx].len;
+ goto reply;
+ case USB_DT_BOS:
+ response_data = conn_descs->bos;
+ response_length = conn_descs->bos_len;
+ goto reply;
+ case USB_DT_DEVICE_QUALIFIER:
+ response_data = conn_descs->qual;
+ response_length = conn_descs->qual_len;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0)
+ return -1;
+ rv = usb_fuzzer_configure(fd);
+ if (rv < 0)
+ return -1;
+ for (ep = 0; ep < index.eps_num; ep++) {
+ rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+ if (rv < 0)
+ exit(1);
+ }
+ done = true;
+ goto reply;
+ default:
+ exit(1);
+ continue;
+ }
+ break;
+ default:
+ exit(1);
+ continue;
+ }
+ struct usb_fuzzer_ep_io_data response;
+ reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ }
+ sleep_ms(200);
+ return fd;
+}
+
+struct vusb_descriptor {
+ uint8_t req_type;
+ uint8_t desc_type;
+ uint32_t len;
+ char data[0];
+} __attribute__((packed));
+
+struct vusb_descriptors {
+ uint32_t len;
+ struct vusb_descriptor* generic;
+ struct vusb_descriptor* descs[0];
+} __attribute__((packed));
+
+struct vusb_response {
+ uint8_t type;
+ uint8_t req;
+ uint32_t len;
+ char data[0];
+} __attribute__((packed));
+
+struct vusb_responses {
+ uint32_t len;
+ struct vusb_response* generic;
+ struct vusb_response* resps[0];
+} __attribute__((packed));
+
+static volatile long syz_usb_control_io(volatile long a0, volatile long a1,
+ volatile long a2)
+{
+ int fd = a0;
+ struct vusb_descriptors* descs = (struct vusb_descriptors*)a1;
+ struct vusb_responses* resps = (struct vusb_responses*)a2;
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+ int rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+ if (rv < 0)
+ return -1;
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ return -1;
+ uint8_t req = event.ctrl.bRequest;
+ uint8_t req_type = event.ctrl.bRequestType & USB_TYPE_MASK;
+ uint8_t desc_type = event.ctrl.wValue >> 8;
+ char* response_data = NULL;
+ uint32_t response_length = 0;
+ if (req == USB_REQ_GET_DESCRIPTOR) {
+ int i;
+ int descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) /
+ sizeof(descs->descs[0]);
+ for (i = 0; i < descs_num; i++) {
+ struct vusb_descriptor* desc = descs->descs[i];
+ if (!desc)
+ continue;
+ if (desc->req_type == req_type && desc->desc_type == desc_type) {
+ response_length = desc->len;
+ if (response_length != 0)
+ response_data = &desc->data[0];
+ goto reply;
+ }
+ }
+ if (descs->generic) {
+ response_data = &descs->generic->data[0];
+ response_length = descs->generic->len;
+ goto reply;
+ }
+ } else {
+ int i;
+ int resps_num = (resps->len - offsetof(struct vusb_responses, resps)) /
+ sizeof(resps->resps[0]);
+ for (i = 0; i < resps_num; i++) {
+ struct vusb_response* resp = resps->resps[i];
+ if (!resp)
+ continue;
+ if (resp->type == req_type && resp->req == req) {
+ response_length = resp->len;
+ if (response_length != 0)
+ response_data = &resp->data[0];
+ goto reply;
+ }
+ }
+ if (resps->generic) {
+ response_data = &resps->generic->data[0];
+ response_length = resps->generic->len;
+ goto reply;
+ }
+ }
+ return -1;
+ struct usb_fuzzer_ep_io_data response;
+
+reply:
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ if (response_length > sizeof(response.data))
+ response_length = 0;
+ response.inner.length = response_length;
+ if (response_data)
+ memcpy(&response.data[0], response_data, response_length);
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ sleep_ms(200);
+ return 0;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+#define SYZ_HAVE_SETUP_TEST 1
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ long res = 0;
+ *(uint8_t*)0x20000000 = 0x12;
+ *(uint8_t*)0x20000001 = 1;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint8_t*)0x20000004 = 0xb0;
+ *(uint8_t*)0x20000005 = 0xf7;
+ *(uint8_t*)0x20000006 = 0x87;
+ *(uint8_t*)0x20000007 = 8;
+ *(uint16_t*)0x20000008 = 0xe41;
+ *(uint16_t*)0x2000000a = 0x4151;
+ *(uint16_t*)0x2000000c = 0x7a8f;
+ *(uint8_t*)0x2000000e = 0;
+ *(uint8_t*)0x2000000f = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 1;
+ *(uint8_t*)0x20000012 = 9;
+ *(uint8_t*)0x20000013 = 2;
+ *(uint16_t*)0x20000014 = 0x12;
+ *(uint8_t*)0x20000016 = 1;
+ *(uint8_t*)0x20000017 = 0;
+ *(uint8_t*)0x20000018 = 0;
+ *(uint8_t*)0x20000019 = 0;
+ *(uint8_t*)0x2000001a = 0;
+ *(uint8_t*)0x2000001b = 9;
+ *(uint8_t*)0x2000001c = 4;
+ *(uint8_t*)0x2000001d = 0;
+ *(uint8_t*)0x2000001e = 2;
+ *(uint8_t*)0x2000001f = 0;
+ *(uint8_t*)0x20000020 = 0xd6;
+ *(uint8_t*)0x20000021 = 0x36;
+ *(uint8_t*)0x20000022 = 0x16;
+ *(uint8_t*)0x20000023 = 0;
+ res = syz_usb_connect(7, 0x24, 0x20000000, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20003e80 = 0x54;
+ *(uint64_t*)0x20003e84 = 0;
+ *(uint64_t*)0x20003e8c = 0x20003c40;
+ *(uint8_t*)0x20003c40 = 0;
+ *(uint8_t*)0x20003c41 = 0xb;
+ *(uint32_t*)0x20003c42 = 0;
+ *(uint64_t*)0x20003e94 = 0;
+ *(uint64_t*)0x20003e9c = 0;
+ *(uint64_t*)0x20003ea4 = 0;
+ *(uint64_t*)0x20003eac = 0;
+ *(uint64_t*)0x20003eb4 = 0;
+ *(uint64_t*)0x20003ebc = 0;
+ *(uint64_t*)0x20003ec4 = 0;
+ *(uint64_t*)0x20003ecc = 0;
+ syz_usb_control_io(r[0], 0, 0x20003e80);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c1dd10546a0f52f25a2cd1eee8596c6e09eece6d.c b/syzkaller-repros/linux/c1dd10546a0f52f25a2cd1eee8596c6e09eece6d.c
new file mode 100644
index 0000000..262a9e4
--- /dev/null
+++ b/syzkaller-repros/linux/c1dd10546a0f52f25a2cd1eee8596c6e09eece6d.c
@@ -0,0 +1,157 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000200 = 0;
+ *(uint32_t*)0x20000208 = 0;
+ *(uint64_t*)0x20000210 = 0x20000180;
+ *(uint64_t*)0x20000180 = 0x200009c0;
+ *(uint32_t*)0x200009c0 = 0x14;
+ *(uint16_t*)0x200009c4 = 0x10;
+ *(uint16_t*)0x200009c6 = 1;
+ *(uint32_t*)0x200009c8 = 0;
+ *(uint32_t*)0x200009cc = 0;
+ *(uint8_t*)0x200009d0 = 0;
+ *(uint8_t*)0x200009d1 = 0;
+ *(uint16_t*)0x200009d2 = htobe16(0xa);
+ *(uint32_t*)0x200009d4 = 0x28;
+ *(uint8_t*)0x200009d8 = 0;
+ *(uint8_t*)0x200009d9 = 0xa;
+ *(uint16_t*)0x200009da = 1;
+ *(uint32_t*)0x200009dc = 0;
+ *(uint32_t*)0x200009e0 = 0;
+ *(uint8_t*)0x200009e4 = 0;
+ *(uint8_t*)0x200009e5 = 0;
+ *(uint16_t*)0x200009e6 = htobe16(0);
+ *(uint16_t*)0x200009e8 = 9;
+ *(uint16_t*)0x200009ea = 1;
+ memcpy((void*)0x200009ec, "syz0\000", 5);
+ *(uint16_t*)0x200009f4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200009f6, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200009f7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200009f7, 0, 7, 1);
+ *(uint32_t*)0x200009f8 = htobe32(1);
+ *(uint32_t*)0x200009fc = 0x14;
+ *(uint16_t*)0x20000a00 = 0x11;
+ *(uint16_t*)0x20000a02 = 3;
+ *(uint32_t*)0x20000a04 = 0;
+ *(uint32_t*)0x20000a08 = 0;
+ *(uint8_t*)0x20000a0c = 0;
+ *(uint8_t*)0x20000a0d = 0;
+ *(uint16_t*)0x20000a0e = htobe16(0xa);
+ *(uint64_t*)0x20000188 = 0x50;
+ *(uint64_t*)0x20000218 = 1;
+ *(uint64_t*)0x20000220 = 0;
+ *(uint64_t*)0x20000228 = 0;
+ *(uint32_t*)0x20000230 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000200ul, 0ul);
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0x20000040;
+ *(uint64_t*)0x20000040 = 0x20000080;
+ memcpy((void*)0x20000080,
+ "\x14\x00\x00\x00\x10\x00\x01\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x0a\x2c\x00\x00\x00\x03\x0a\x5b\xa6\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00"
+ "\x00\x09\x00\x03\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x14\x00\x00\x00"
+ "\x11\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a",
+ 84);
+ *(uint64_t*)0x20000048 = 0x54;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000140ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint64_t*)0x20000250 = 0x20000200;
+ *(uint64_t*)0x20000200 = 0x20000140;
+ *(uint32_t*)0x20000140 = 0x14;
+ *(uint16_t*)0x20000144 = 0x10;
+ *(uint16_t*)0x20000146 = 1;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint32_t*)0x2000014c = 0;
+ *(uint8_t*)0x20000150 = 0;
+ *(uint8_t*)0x20000151 = 0;
+ *(uint16_t*)0x20000152 = htobe16(0xa);
+ *(uint32_t*)0x20000154 = 0x58;
+ *(uint8_t*)0x20000158 = 6;
+ *(uint8_t*)0x20000159 = 0xa;
+ *(uint16_t*)0x2000015a = 0x401;
+ *(uint32_t*)0x2000015c = 0;
+ *(uint32_t*)0x20000160 = 0;
+ *(uint8_t*)0x20000164 = 0;
+ *(uint8_t*)0x20000165 = 0;
+ *(uint16_t*)0x20000166 = htobe16(0);
+ *(uint16_t*)0x20000168 = 9;
+ *(uint16_t*)0x2000016a = 2;
+ memcpy((void*)0x2000016c, "syz0\000", 5);
+ *(uint16_t*)0x20000174 = 9;
+ *(uint16_t*)0x20000176 = 1;
+ memcpy((void*)0x20000178, "syz0\000", 5);
+ *(uint16_t*)0x20000180 = 0x2c;
+ STORE_BY_BITMASK(uint16_t, , 0x20000182, 4, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000183, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000183, 1, 7, 1);
+ *(uint16_t*)0x20000184 = 0x28;
+ STORE_BY_BITMASK(uint16_t, , 0x20000186, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000187, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000187, 1, 7, 1);
+ *(uint16_t*)0x20000188 = 0xb;
+ *(uint16_t*)0x2000018a = 1;
+ memcpy((void*)0x2000018c, "socket\000", 7);
+ *(uint16_t*)0x20000194 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000196, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000197, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000197, 1, 7, 1);
+ *(uint16_t*)0x20000198 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000019a, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019b, 0, 7, 1);
+ *(uint32_t*)0x2000019c = htobe32(0xa);
+ *(uint16_t*)0x200001a0 = 0xb;
+ *(uint16_t*)0x200001a2 = 1;
+ memcpy((void*)0x200001a4, "tunnel\000", 7);
+ *(uint32_t*)0x200001ac = 0x14;
+ *(uint16_t*)0x200001b0 = 0x11;
+ *(uint16_t*)0x200001b2 = 1;
+ *(uint32_t*)0x200001b4 = 0;
+ *(uint32_t*)0x200001b8 = 0;
+ *(uint8_t*)0x200001bc = 0;
+ *(uint8_t*)0x200001bd = 0;
+ *(uint16_t*)0x200001be = htobe16(0xa);
+ *(uint64_t*)0x20000208 = 0x80;
+ *(uint64_t*)0x20000258 = 1;
+ *(uint64_t*)0x20000260 = 0;
+ *(uint64_t*)0x20000268 = 0;
+ *(uint32_t*)0x20000270 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000240ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c37ecd4167eea34e634df7261019d07996dfec9e.c b/syzkaller-repros/linux/c37ecd4167eea34e634df7261019d07996dfec9e.c
new file mode 100644
index 0000000..e53d697
--- /dev/null
+++ b/syzkaller-repros/linux/c37ecd4167eea34e634df7261019d07996dfec9e.c
@@ -0,0 +1,461 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_fsetxattr, -1, 0ul, 0ul, 0ul, 0ul);
+ syscall(__NR_ioctl, -1, 0x4004af61ul, 0ul);
+ syscall(__NR_setsockopt, -1, 1ul, 0x19ul, 0ul, 0ul);
+ memcpy((void*)0x200003c0, "/dev/dri/card#\000", 15);
+ res = syz_open_dev(0x200003c0, 2, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000000 = 0x80;
+ *(uint32_t*)0x20000004 = 1;
+ *(uint32_t*)0x20000008 = 0xfb;
+ *(uint16_t*)0x2000000c = 0;
+ syscall(__NR_setsockopt, -1, 0ul, 2ul, 0x20000000ul, 0x10ul);
+ inject_fault(10);
+ syscall(__NR_ioctl, r[0], 0xffffffffffffffb2ul, 0x20000000ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c3960c948f92ebce8f1790d87d20ad6d0a8befa8.c b/syzkaller-repros/linux/c3960c948f92ebce8f1790d87d20ad6d0a8befa8.c
new file mode 100644
index 0000000..82b8e9e
--- /dev/null
+++ b/syzkaller-repros/linux/c3960c948f92ebce8f1790d87d20ad6d0a8befa8.c
@@ -0,0 +1,473 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 0x14 + procid * 2);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, -1, 0x40045431ul, 0ul);
+ memcpy((void*)0x200000c0, "#! ", 3);
+ memcpy((void*)0x200000c3, "./file0", 7);
+ *(uint8_t*)0x200000ca = 0xa;
+ syscall(__NR_write, r[0], 0x200000c0ul, 0xbul);
+ syscall(__NR_ioctl, -1, 0x802c542aul, 0ul);
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0ul, 0ul);
+ memcpy((void*)0x20000000, "/dev/fb0\000", 9);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0x20;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ *(uint32_t*)0x200000b4 = 0;
+ *(uint32_t*)0x200000b8 = 0;
+ *(uint32_t*)0x200000bc = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint32_t*)0x200000cc = 0;
+ *(uint32_t*)0x200000d0 = 0;
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ syscall(__NR_ioctl, r[1], 0x4601ul, 0x20000040ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c3c734ede90bc97ce7a49fa266e7e6ac275ac15c.c b/syzkaller-repros/linux/c3c734ede90bc97ce7a49fa266e7e6ac275ac15c.c
new file mode 100644
index 0000000..7090d3f
--- /dev/null
+++ b/syzkaller-repros/linux/c3c734ede90bc97ce7a49fa266e7e6ac275ac15c.c
@@ -0,0 +1,278 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+
+ memcpy((void*)0x20000000, "./bus\000", 6);
+ syscall(__NR_creat, 0x20000000ul, 0xfffffffffffffffcul);
+ memcpy((void*)0x20000280, "/dev/loop", 9);
+ *(uint8_t*)0x20000289 = 0x30;
+ *(uint8_t*)0x2000028a = 0;
+ memcpy((void*)0x200002c0, "./bus\000", 6);
+ memcpy((void*)0x20000300, "exfat\000", 6);
+ syscall(__NR_mount, 0x20000280ul, 0x200002c0ul, 0x20000300ul, 0x400000ul,
+ 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c43d832d97fb6f646cee396845c6f7a1a625559e.c b/syzkaller-repros/linux/c43d832d97fb6f646cee396845c6f7a1a625559e.c
new file mode 100644
index 0000000..e08a890
--- /dev/null
+++ b/syzkaller-repros/linux/c43d832d97fb6f646cee396845c6f7a1a625559e.c
@@ -0,0 +1,134 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 1, 2, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ memcpy((void*)0x20000000, "trusted.syz", 12);
+ syscall(__NR_fgetxattr, r[0], 0x20000000, 0x200000c0, 0x37);
+ break;
+ case 2:
+ *(uint16_t*)0x20000040 = 1;
+ memcpy((void*)0x20000042,
+ "\x2e\x2f\x66\x69\x6c\x65\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 108);
+ syscall(__NR_bind, r[0], 0x20000040, 0x6e);
+ break;
+ case 3:
+ *(uint16_t*)0x20000180 = 1;
+ memcpy((void*)0x20000182,
+ "\x2e\x2f\x66\x69\x6c\x65\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 108);
+ syscall(__NR_connect, r[0], 0x20000180, 0x6e);
+ break;
+ case 4:
+ memcpy((void*)0x20000100, "/dev/full", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000100, 0xa00, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 5:
+ syscall(__NR_dup2, r[1], r[0]);
+ break;
+ }
+}
+
+void loop()
+{
+ execute(6);
+ collide = 1;
+ execute(6);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c47b1b7f05e955d0f05419eadbdf5bf7c2d9ae00.c b/syzkaller-repros/linux/c47b1b7f05e955d0f05419eadbdf5bf7c2d9ae00.c
new file mode 100644
index 0000000..243bfe3
--- /dev/null
+++ b/syzkaller-repros/linux/c47b1b7f05e955d0f05419eadbdf5bf7c2d9ae00.c
@@ -0,0 +1,426 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x200001c0 = 3;
+ syscall(__NR_ioctl, r[0], 0x541cul, 0x200001c0ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ *(uint8_t*)0x200000c0 = 2;
+ *(uint16_t*)0x200000c1 = 0;
+ *(uint16_t*)0x200000c3 = 0;
+ *(uint16_t*)0x200000c5 = 0;
+ *(uint16_t*)0x200000c7 = 1;
+ *(uint16_t*)0x200000c9 = 1;
+ syscall(__NR_ioctl, r[1], 0x541cul, 0x200000c0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c765b46408bf5af4eace4188e78ec21cc1c93a0c.c b/syzkaller-repros/linux/c765b46408bf5af4eace4188e78ec21cc1c93a0c.c
new file mode 100644
index 0000000..bcc6b7b
--- /dev/null
+++ b/syzkaller-repros/linux/c765b46408bf5af4eace4188e78ec21cc1c93a0c.c
@@ -0,0 +1,879 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[6] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socketpair, 1ul, 1ul, 0ul, 0x20000000ul);
+ if (res != -1)
+ r[0] = *(uint32_t*)0x20000004;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000340, "erspan0\000\000\000\000\000\000\000\000\000", 16);
+ *(uint32_t*)0x20000350 = 0;
+ res = syscall(__NR_ioctl, r[0], 0x8933ul, 0x20000340ul);
+ if (res != -1)
+ r[2] = *(uint32_t*)0x20000350;
+ syscall(__NR_ioctl, -1, 0x8933ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[3] = res;
+ res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ if (res != -1)
+ r[4] = res;
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint64_t*)0x200001d0 = 0x20000180;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint64_t*)0x20000188 = 0;
+ *(uint64_t*)0x200001d8 = 1;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001f0 = 0;
+ syscall(__NR_sendmsg, r[4], 0x200001c0ul, 0ul);
+ *(uint32_t*)0x20000200 = 0x14;
+ res = syscall(__NR_getsockname, r[4], 0x20000100ul, 0x20000200ul);
+ if (res != -1)
+ r[5] = *(uint32_t*)0x20000104;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint64_t*)0x20000190 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000380;
+ *(uint32_t*)0x20000380 = 0x44;
+ *(uint16_t*)0x20000384 = 0x10;
+ *(uint16_t*)0x20000386 = 0x401;
+ *(uint32_t*)0x20000388 = 0;
+ *(uint32_t*)0x2000038c = 0;
+ *(uint8_t*)0x20000390 = 0;
+ *(uint8_t*)0x20000391 = 0;
+ *(uint16_t*)0x20000392 = 0;
+ *(uint32_t*)0x20000394 = r[5];
+ *(uint32_t*)0x20000398 = 0;
+ *(uint32_t*)0x2000039c = 0;
+ *(uint16_t*)0x200003a0 = 0x24;
+ *(uint16_t*)0x200003a2 = 0x12;
+ *(uint16_t*)0x200003a4 = 0xc;
+ *(uint16_t*)0x200003a6 = 1;
+ memcpy((void*)0x200003a8, "bridge\000", 7);
+ *(uint16_t*)0x200003b0 = 0x14;
+ *(uint16_t*)0x200003b2 = 2;
+ *(uint16_t*)0x200003b4 = 8;
+ *(uint16_t*)0x200003b6 = 7;
+ *(uint8_t*)0x200003b8 = 5;
+ *(uint16_t*)0x200003bc = 8;
+ *(uint16_t*)0x200003be = 0x1d;
+ *(uint32_t*)0x200003c0 = 3;
+ *(uint64_t*)0x200000c8 = 0x44;
+ *(uint64_t*)0x20000198 = 1;
+ *(uint64_t*)0x200001a0 = 0;
+ *(uint64_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001b0 = 0;
+ syscall(__NR_sendmsg, r[3], 0x20000180ul, 0ul);
+ *(uint64_t*)0x20000140 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint64_t*)0x20000150 = 0x200006c0;
+ *(uint64_t*)0x200006c0 = 0x200000c0;
+ memcpy((void*)0x200000c0,
+ "\x28\x00\x00\x00\x10\x00\x01\x04\x00\x00\x40\x00\x00\x00\x00\x00\x00"
+ "\x00\x1e\xa6",
+ 20);
+ *(uint32_t*)0x200000d4 = r[2];
+ memcpy((void*)0x200000d8, "\000\000\000\000\000\000\000\000\b\000\n\000", 12);
+ *(uint32_t*)0x200000e4 = r[5];
+ *(uint64_t*)0x200006c8 = 0x28;
+ *(uint64_t*)0x20000158 = 1;
+ *(uint64_t*)0x20000160 = 0;
+ *(uint64_t*)0x20000168 = 0;
+ *(uint32_t*)0x20000170 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000140ul, 0ul);
+ syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c89260cf352b3c907c9899403b65727b666b591c.c b/syzkaller-repros/linux/c89260cf352b3c907c9899403b65727b666b591c.c
new file mode 100644
index 0000000..ed85d46
--- /dev/null
+++ b/syzkaller-repros/linux/c89260cf352b3c907c9899403b65727b666b591c.c
@@ -0,0 +1,314 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000100, "trusted.overlay.upper\000", 22);
+ syscall(__NR_setxattr, 0ul, 0x20000100ul, 0ul, 0ul, 0ul);
+ res = syz_open_dev(0xc, 4, 0x14);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x20000000 = 2;
+ *(uint16_t*)0x20000001 = 3;
+ *(uint16_t*)0x20000003 = 0;
+ *(uint16_t*)0x20000005 = 0;
+ *(uint16_t*)0x20000007 = 3;
+ *(uint16_t*)0x20000009 = 1;
+ syscall(__NR_ioctl, r[0], 0x541cul, 0x20000000ul);
+ res = syz_open_dev(0xc, 4, 0x14);
+ if (res != -1)
+ r[1] = res;
+ *(uint8_t*)0x20000000 = 2;
+ *(uint16_t*)0x20000001 = 3;
+ *(uint16_t*)0x20000003 = 0;
+ *(uint16_t*)0x20000005 = 0;
+ *(uint16_t*)0x20000007 = 3;
+ *(uint16_t*)0x20000009 = 1;
+ syscall(__NR_ioctl, r[1], 0x4b61ul, 0x20000000ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/c9da3c745a77c2b3b286c9261e808853ae4b4304.c b/syzkaller-repros/linux/c9da3c745a77c2b3b286c9261e808853ae4b4304.c
new file mode 100644
index 0000000..d66288f
--- /dev/null
+++ b/syzkaller-repros/linux/c9da3c745a77c2b3b286c9261e808853ae4b4304.c
@@ -0,0 +1,307 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x50;
+ *(uint8_t*)0x20000004 = 2;
+ *(uint8_t*)0x20000005 = 6;
+ *(uint16_t*)0x20000006 = 1;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 0;
+ *(uint16_t*)0x20000012 = htobe16(0);
+ *(uint16_t*)0x20000014 = 9;
+ *(uint16_t*)0x20000016 = 2;
+ memcpy((void*)0x20000018, "syz0\000", 5);
+ *(uint16_t*)0x20000020 = 0x15;
+ *(uint16_t*)0x20000022 = 3;
+ memcpy((void*)0x20000024, "hash:ip,port,net\000", 17);
+ *(uint16_t*)0x20000038 = 5;
+ *(uint16_t*)0x2000003a = 1;
+ *(uint8_t*)0x2000003c = 7;
+ *(uint16_t*)0x20000040 = 5;
+ *(uint16_t*)0x20000042 = 4;
+ *(uint8_t*)0x20000044 = 0;
+ *(uint16_t*)0x20000048 = 5;
+ *(uint16_t*)0x2000004a = 5;
+ *(uint8_t*)0x2000004c = 0xa;
+ *(uint64_t*)0x200002c8 = 0x50;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_getsockopt, r[1], 1ul, 0x23ul, 0ul, 0ul);
+ syscall(__NR_sendmsg, r[1], 0ul, 0x20009040ul);
+ syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_sendmsg, -1, 0ul, 5ul);
+ *(uint64_t*)0x20000400 = 0;
+ *(uint32_t*)0x20000408 = 0;
+ *(uint64_t*)0x20000410 = 0x200003c0;
+ *(uint64_t*)0x200003c0 = 0x20000440;
+ *(uint32_t*)0x20000440 = 0x158;
+ *(uint8_t*)0x20000444 = 0xb;
+ *(uint8_t*)0x20000445 = 6;
+ *(uint16_t*)0x20000446 = 1;
+ *(uint32_t*)0x20000448 = 0x70bd29;
+ *(uint32_t*)0x2000044c = 0x25dfdbfd;
+ *(uint8_t*)0x20000450 = 7;
+ *(uint8_t*)0x20000451 = 0;
+ *(uint16_t*)0x20000452 = htobe16(9);
+ *(uint16_t*)0x20000454 = 5;
+ *(uint16_t*)0x20000456 = 1;
+ *(uint8_t*)0x20000458 = 7;
+ *(uint16_t*)0x2000045c = 0x20;
+ STORE_BY_BITMASK(uint16_t, , 0x2000045e, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000045f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000045f, 1, 7, 1);
+ *(uint16_t*)0x20000460 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x20000462, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000463, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000463, 1, 7, 1);
+ *(uint16_t*)0x20000464 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000466, 0x18, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000467, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000467, 0, 7, 1);
+ *(uint64_t*)0x20000468 = htobe64(0);
+ *(uint16_t*)0x20000470 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000472, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 1, 7, 1);
+ *(uint16_t*)0x20000474 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000476, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000477, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000477, 0, 7, 1);
+ *(uint32_t*)0x20000478 = htobe32(9);
+ *(uint16_t*)0x2000047c = 0x38;
+ STORE_BY_BITMASK(uint16_t, , 0x2000047e, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000047f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000047f, 1, 7, 1);
+ *(uint16_t*)0x20000480 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000482, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000483, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000483, 1, 7, 1);
+ *(uint16_t*)0x20000484 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000486, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000487, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000487, 0, 7, 1);
+ *(uint32_t*)0x20000488 = htobe32(0);
+ *(uint16_t*)0x2000048c = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x2000048e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000048f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000048f, 1, 7, 1);
+ *(uint16_t*)0x20000490 = 0xa;
+ *(uint16_t*)0x20000492 = 0x11;
+ *(uint8_t*)0x20000494 = 0xaa;
+ *(uint8_t*)0x20000495 = 0xaa;
+ *(uint8_t*)0x20000496 = 0xaa;
+ *(uint8_t*)0x20000497 = 0xaa;
+ *(uint8_t*)0x20000498 = 0xaa;
+ *(uint8_t*)0x20000499 = 0xbb;
+ *(uint16_t*)0x2000049c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000049e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000049f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000049f, 1, 7, 1);
+ *(uint16_t*)0x200004a0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200004a2, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004a3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004a3, 0, 7, 1);
+ *(uint32_t*)0x200004a4 = htobe32(0xfffffffb);
+ *(uint16_t*)0x200004a8 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200004aa, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004ab, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004ab, 1, 7, 1);
+ *(uint16_t*)0x200004ac = 5;
+ *(uint16_t*)0x200004ae = 0x15;
+ *(uint8_t*)0x200004b0 = 0xe1;
+ *(uint16_t*)0x200004b4 = 0x38;
+ STORE_BY_BITMASK(uint16_t, , 0x200004b6, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004b7, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004b7, 1, 7, 1);
+ *(uint16_t*)0x200004b8 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200004ba, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004bb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004bb, 1, 7, 1);
+ *(uint16_t*)0x200004bc = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x200004be, 0x1d, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004bf, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004bf, 0, 7, 1);
+ *(uint16_t*)0x200004c0 = htobe16(7);
+ *(uint16_t*)0x200004c4 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200004c6, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004c7, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004c7, 1, 7, 1);
+ *(uint16_t*)0x200004c8 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200004ca, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004cb, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004cb, 0, 7, 1);
+ *(uint32_t*)0x200004cc = htobe32(0xfff);
+ *(uint16_t*)0x200004d0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200004d2, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004d3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004d3, 1, 7, 1);
+ *(uint16_t*)0x200004d4 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x200004d6, 0x1d, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004d7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004d7, 0, 7, 1);
+ *(uint16_t*)0x200004d8 = htobe16(0x6d);
+ *(uint16_t*)0x200004dc = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x200004de, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004df, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004df, 1, 7, 1);
+ *(uint16_t*)0x200004e0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200004e2, 0x1b, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004e3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004e3, 0, 7, 1);
+ *(uint64_t*)0x200004e4 = htobe64(9);
+ *(uint16_t*)0x200004ec = 0x38;
+ STORE_BY_BITMASK(uint16_t, , 0x200004ee, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004ef, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004ef, 1, 7, 1);
+ *(uint16_t*)0x200004f0 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x200004f2, 0x14, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004f3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004f3, 1, 7, 1);
+ *(uint16_t*)0x200004f4 = 0x14;
+ STORE_BY_BITMASK(uint16_t, , 0x200004f6, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200004f7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200004f7, 0, 7, 1);
+ *(uint8_t*)0x200004f8 = 0xfe;
+ *(uint8_t*)0x200004f9 = 0x80;
+ *(uint8_t*)0x200004fa = 0;
+ *(uint8_t*)0x200004fb = 0;
+ *(uint8_t*)0x200004fc = 0;
+ *(uint8_t*)0x200004fd = 0;
+ *(uint8_t*)0x200004fe = 0;
+ *(uint8_t*)0x200004ff = 0;
+ *(uint8_t*)0x20000500 = 0;
+ *(uint8_t*)0x20000501 = 0;
+ *(uint8_t*)0x20000502 = 0;
+ *(uint8_t*)0x20000503 = 0;
+ *(uint8_t*)0x20000504 = 0;
+ *(uint8_t*)0x20000505 = 0;
+ *(uint8_t*)0x20000506 = 0;
+ *(uint8_t*)0x20000507 = 0xbb;
+ *(uint16_t*)0x20000508 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000050a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000050b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000050b, 1, 7, 1);
+ *(uint16_t*)0x2000050c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000050e, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000050f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000050f, 0, 7, 1);
+ *(uint32_t*)0x20000510 = htobe32(0);
+ *(uint16_t*)0x20000514 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000516, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000517, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000517, 0, 7, 1);
+ *(uint32_t*)0x20000518 = htobe32(7);
+ *(uint16_t*)0x2000051c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000051e, 0x1c, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000051f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000051f, 0, 7, 1);
+ *(uint32_t*)0x20000520 = htobe32(0xcac63400);
+ *(uint16_t*)0x20000524 = 9;
+ *(uint16_t*)0x20000526 = 2;
+ memcpy((void*)0x20000528, "syz0\000", 5);
+ *(uint16_t*)0x20000530 = 0x60;
+ STORE_BY_BITMASK(uint16_t, , 0x20000532, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000533, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000533, 1, 7, 1);
+ *(uint16_t*)0x20000534 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x20000536, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000537, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000537, 1, 7, 1);
+ *(uint16_t*)0x20000538 = 9;
+ *(uint16_t*)0x2000053a = 0x12;
+ memcpy((void*)0x2000053c, "syz0\000", 5);
+ *(uint16_t*)0x20000544 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x20000546, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000547, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000547, 1, 7, 1);
+ *(uint16_t*)0x20000548 = 0xa;
+ *(uint16_t*)0x2000054a = 0x11;
+ *(uint8_t*)0x2000054c = 0xaa;
+ *(uint8_t*)0x2000054d = 0xaa;
+ *(uint8_t*)0x2000054e = 0xaa;
+ *(uint8_t*)0x2000054f = 0xaa;
+ *(uint8_t*)0x20000550 = 0xaa;
+ *(uint8_t*)0x20000551 = 0x32;
+ *(uint16_t*)0x20000554 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000556, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000557, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000557, 1, 7, 1);
+ *(uint16_t*)0x20000558 = 6;
+ STORE_BY_BITMASK(uint16_t, , 0x2000055a, 0x1d, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000055b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000055b, 0, 7, 1);
+ *(uint16_t*)0x2000055c = htobe16(0x40);
+ *(uint16_t*)0x20000560 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x20000562, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000563, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000563, 1, 7, 1);
+ *(uint16_t*)0x20000564 = 9;
+ *(uint16_t*)0x20000566 = 0x13;
+ memcpy((void*)0x20000568, "syz0\000", 5);
+ *(uint16_t*)0x20000570 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x20000572, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000573, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000573, 1, 7, 1);
+ *(uint16_t*)0x20000574 = 9;
+ *(uint16_t*)0x20000576 = 0x12;
+ memcpy((void*)0x20000578, "syz0\000", 5);
+ *(uint16_t*)0x20000580 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x20000582, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000583, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000583, 1, 7, 1);
+ *(uint16_t*)0x20000584 = 9;
+ *(uint16_t*)0x20000586 = 0x12;
+ memcpy((void*)0x20000588, "syz0\000", 5);
+ *(uint16_t*)0x20000590 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000592, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000593, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000593, 0, 7, 1);
+ *(uint32_t*)0x20000594 = htobe32(6);
+ *(uint64_t*)0x200003c8 = 0x158;
+ *(uint64_t*)0x20000418 = 1;
+ *(uint64_t*)0x20000420 = 0;
+ *(uint64_t*)0x20000428 = 0;
+ *(uint32_t*)0x20000430 = 0x810;
+ syscall(__NR_sendmsg, r[2], 0x20000400ul, 0x4000100ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/cabdcf8dab83f89b7efe104a10de67a17f1ab902.c b/syzkaller-repros/linux/cabdcf8dab83f89b7efe104a10de67a17f1ab902.c
new file mode 100644
index 0000000..f2b65f2
--- /dev/null
+++ b/syzkaller-repros/linux/cabdcf8dab83f89b7efe104a10de67a17f1ab902.c
@@ -0,0 +1,47 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+long r[10];
+void loop()
+{
+ memset(r, -1, sizeof(r));
+ r[0] = syscall(__NR_mmap, 0x20000000ul, 0xfff000ul, 0x3ul, 0x32ul,
+ 0xfffffffffffffffful, 0x0ul);
+ r[1] = syscall(__NR_pipe, 0x20dfbff8ul);
+ if (r[1] != -1)
+ r[2] = *(uint32_t*)0x20dfbff8;
+ if (r[1] != -1)
+ r[3] = *(uint32_t*)0x20dfbffc;
+ r[4] = syscall(__NR_socket, 0x2ul, 0x1ul, 0x0ul);
+ *(uint64_t*)0x201a2000 = (uint64_t)0x20dc6000;
+ *(uint64_t*)0x201a2008 = (uint64_t)0xc3;
+ memcpy((void*)0x20dc6000,
+ "\x19\x7e\xf0\x49\xe6\x89\x5d\xd0\x05\x2f\x3e\x98\x04\x5a\x85"
+ "\x09\x15\x3c\x1e\x6f\x68\x1c\xf9\x9c\x19\xca\x07\x2f\x28\x09"
+ "\xd8\x33\x79\x82\xd7\x7b\xdb\xda\x3c\x32\x43\x31\x2a\x8b\x2a"
+ "\x75\x8c\x4d\xb7\x5c\xa8\x40\x48\x9d\xac\x77\xf1\x66\xf8\xdd"
+ "\xa8\x65\xd9\x7f\xdc\xe1\x1e\xd8\x9e\xd5\x86\x51\x9d\x8d\xaf"
+ "\x92\x11\x91\xdd\xf2\x3a\x4a\x0a\x3f\x91\xa5\xed\x28\xaa\x84"
+ "\xe7\x3a\x81\xb6\xda\x06\xe6\xa7\x67\x6a\x3b\x75\xa9\xd2\x6f"
+ "\xf6\x9d\xc1\x66\xc8\xbc\x9e\x1c\xef\x52\x22\x6b\xf3\xc0\x1f"
+ "\xff\xa8\x41\x33\x2e\x78\xf2\x2d\x1c\x0c\xbd\x3f\x41\x46\xb3"
+ "\x9d\x44\x49\xfc\xb8\x73\x33\xd6\x55\xe6\x04\x9b\x8f\x6d\x6a"
+ "\xe8\xc5\xdf\x54\x75\x75\x5e\x2a\xa2\xf7\xd7\x51\xca\x26\xce"
+ "\x5f\x2d\xf6\x30\x03\x50\x06\x9b\x4b\xc8\x4f\xbc\x77\xa2\x8f"
+ "\xda\xb3\x40\x39\xda\x6b\x26\xd7\x6b\x79\x06\x7f\x56\xb2\x88",
+ 195);
+ r[8] = syscall(__NR_writev, r[3], 0x201a2000ul, 0x1ul);
+ r[9] = syscall(__NR_splice, r[2], 0x0ul, r[4], 0x0ul, 0x9ul, 0x4ul);
+}
+
+int main()
+{
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/cbb7dab789d8f23306187cfc894a5a65d02b6e95.c b/syzkaller-repros/linux/cbb7dab789d8f23306187cfc894a5a65d02b6e95.c
new file mode 100644
index 0000000..ab521de
--- /dev/null
+++ b/syzkaller-repros/linux/cbb7dab789d8f23306187cfc894a5a65d02b6e95.c
@@ -0,0 +1,605 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 12; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ memcpy((void*)0x200000c0, "\xb6", 1);
+ syscall(__NR_ioctl, r[0], 0x4b61ul, 0x200000c0ul);
+ break;
+ case 2:
+ syz_open_dev(0xc, 4, 0x14 + procid * 2);
+ break;
+ case 3:
+ syscall(__NR_ioctl, -1, 0x4b72ul, 0ul);
+ break;
+ case 4:
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0xc823035de211e4d9ul,
+ 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 5:
+ syscall(__NR_ioctl, r[1], 0x40086602ul, 0ul);
+ break;
+ case 6:
+ *(uint16_t*)0x200000c0 = 0xf9;
+ *(uint16_t*)0x200000c2 = 0x101;
+ *(uint16_t*)0x200000c4 = 0x1f;
+ syscall(__NR_ioctl, -1, 0x5603ul, 0x200000c0ul);
+ break;
+ case 7:
+ syscall(__NR_read, -1, 0ul, 0ul);
+ break;
+ case 8:
+ syscall(__NR_ioctl, -1, 0x4b44ul, 0ul);
+ break;
+ case 9:
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 10:
+ syscall(__NR_ioctl, -1, 0x4b46ul, 0ul);
+ break;
+ case 11:
+ *(uint32_t*)0x20000000 = 3;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0x15;
+ *(uint32_t*)0x20000010 = 0;
+ *(uint64_t*)0x20000018 = 0;
+ syscall(__NR_ioctl, r[2], 0x4b72ul, 0x20000000ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/ccd3afec24eaa9bb5ca67bc5098f274107a621b3.c b/syzkaller-repros/linux/ccd3afec24eaa9bb5ca67bc5098f274107a621b3.c
new file mode 100644
index 0000000..1131035
--- /dev/null
+++ b/syzkaller-repros/linux/ccd3afec24eaa9bb5ca67bc5098f274107a621b3.c
@@ -0,0 +1,148 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static uintptr_t syz_open_pts(uintptr_t a0, uintptr_t a1)
+{
+ int ptyno = 0;
+ if (ioctl(a0, TIOCGPTN, &ptyno))
+ return -1;
+ char buf[128];
+ sprintf(buf, "/dev/pts/%d", ptyno);
+ return open(buf, a1, 0);
+}
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000100, "/dev/ptmx", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000100, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint32_t*)0x203b9fdc = 0;
+ *(uint32_t*)0x203b9fe0 = 0;
+ *(uint32_t*)0x203b9fe4 = 0;
+ *(uint32_t*)0x203b9fe8 = 0;
+ *(uint8_t*)0x203b9fec = 0;
+ *(uint8_t*)0x203b9fed = 0;
+ *(uint8_t*)0x203b9fee = 0;
+ *(uint8_t*)0x203b9fef = 0;
+ *(uint32_t*)0x203b9ff0 = 0;
+ *(uint32_t*)0x203b9ff4 = 0;
+ *(uint32_t*)0x203b9ff8 = 0;
+ *(uint32_t*)0x203b9ffc = 0;
+ syscall(__NR_ioctl, r[0], 0x40045431, 0x203b9fdc);
+ break;
+ case 2:
+ *(uint16_t*)0x20000040 = 0;
+ *(uint16_t*)0x20000042 = 0;
+ *(uint16_t*)0x20000044 = 0;
+ *(uint16_t*)0x20000046 = 0;
+ *(uint8_t*)0x20000048 = 0;
+ *(uint8_t*)0x20000049 = 0;
+ *(uint8_t*)0x2000004a = 0;
+ *(uint8_t*)0x2000004b = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint8_t*)0x20000050 = 0;
+ syscall(__NR_ioctl, r[0], 0x5407, 0x20000040);
+ break;
+ case 3:
+ res = syz_open_pts(r[0], 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 4:
+ *(uint64_t*)0x20022f90 = 0x20a94fff;
+ *(uint64_t*)0x20022f98 = 1;
+ syscall(__NR_readv, r[1], 0x20022f90, 1);
+ break;
+ }
+}
+
+void loop()
+{
+ execute(5);
+ collide = 1;
+ execute(5);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d1e22c7dfb66c4f88fdf305ee211f0f0a099c647.c b/syzkaller-repros/linux/d1e22c7dfb66c4f88fdf305ee211f0f0a099c647.c
new file mode 100644
index 0000000..cc73f59
--- /dev/null
+++ b/syzkaller-repros/linux/d1e22c7dfb66c4f88fdf305ee211f0f0a099c647.c
@@ -0,0 +1,864 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ }
+ write_file("/syzcgroup/unified/cgroup.subtree_control",
+ "+cpu +memory +io +pids +rdma");
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+ "cpuset,cpuacct,perf_event,hugetlb")) {
+ }
+ write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0,
+ "net_cls,net_prio,devices,freezer")) {
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ }
+}
+
+static void setup_cgroups_loop()
+{
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ }
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+ setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0)
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ setup_cgroups_loop();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setup_cgroups_test();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 2, 5, 0);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_sendto, r[0], 0, 0, 0, 0, 0);
+ NONFAILING(*(uint16_t*)0x20000000 = 2);
+ NONFAILING(*(uint16_t*)0x20000002 = htobe16(0x4e22));
+ NONFAILING(*(uint8_t*)0x20000004 = 0xac);
+ NONFAILING(*(uint8_t*)0x20000005 = 0x14);
+ NONFAILING(*(uint8_t*)0x20000006 = 0x14);
+ NONFAILING(*(uint8_t*)0x20000007 = 0xbb);
+ syscall(__NR_bind, r[0], 0x20000000, 0x10);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_binfmt_misc();
+ setup_leak();
+ install_segv_handler();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d247615dab7b953b6787c9f5cfbd0c0bd4007a2d.c b/syzkaller-repros/linux/d247615dab7b953b6787c9f5cfbd0c0bd4007a2d.c
new file mode 100644
index 0000000..d59696f
--- /dev/null
+++ b/syzkaller-repros/linux/d247615dab7b953b6787c9f5cfbd0c0bd4007a2d.c
@@ -0,0 +1,592 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ exit(1);
+ }
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+static long syz_genetlink_get_family_id(volatile long name)
+{
+ char buf[512] = {0};
+ struct nlmsghdr* hdr = (struct nlmsghdr*)buf;
+ struct genlmsghdr* genlhdr = (struct genlmsghdr*)NLMSG_DATA(hdr);
+ struct nlattr* attr = (struct nlattr*)(genlhdr + 1);
+ hdr->nlmsg_len =
+ sizeof(*hdr) + sizeof(*genlhdr) + sizeof(*attr) + GENL_NAMSIZ;
+ hdr->nlmsg_type = GENL_ID_CTRL;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ genlhdr->cmd = CTRL_CMD_GETFAMILY;
+ attr->nla_type = CTRL_ATTR_FAMILY_NAME;
+ attr->nla_len = sizeof(*attr) + GENL_NAMSIZ;
+ strncpy((char*)(attr + 1), (char*)name, GENL_NAMSIZ);
+ struct iovec iov = {hdr, hdr->nlmsg_len};
+ struct sockaddr_nl addr = {0};
+ addr.nl_family = AF_NETLINK;
+ int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (fd == -1) {
+ return -1;
+ }
+ struct msghdr msg = {&addr, sizeof(addr), &iov, 1, NULL, 0, 0};
+ if (sendmsg(fd, &msg, 0) == -1) {
+ close(fd);
+ return -1;
+ }
+ ssize_t n = recv(fd, buf, sizeof(buf), 0);
+ close(fd);
+ if (n <= 0) {
+ return -1;
+ }
+ if (hdr->nlmsg_type != GENL_ID_CTRL) {
+ return -1;
+ }
+ for (; (char*)attr < buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID)
+ return *(uint16_t*)(attr + 1);
+ }
+ return -1;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0x0};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000000, "ethtool\000", 8);
+ res = syz_genetlink_get_family_id(0x20000000);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint64_t*)0x20000250 = 0x200001c0;
+ *(uint64_t*)0x200001c0 = 0x20000040;
+ *(uint32_t*)0x20000040 = 0x40;
+ *(uint16_t*)0x20000044 = r[1];
+ *(uint16_t*)0x20000046 = 1;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint8_t*)0x20000050 = 5;
+ *(uint8_t*)0x20000051 = 0;
+ *(uint16_t*)0x20000052 = 0;
+ *(uint16_t*)0x20000054 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x20000056, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000057, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000057, 1, 7, 1);
+ *(uint16_t*)0x20000058 = 0x14;
+ *(uint16_t*)0x2000005a = 2;
+ memcpy((void*)0x2000005c, "syz_tun\000\000\000\000\000\000\000\000\000", 16);
+ *(uint16_t*)0x2000006c = 0x14;
+ STORE_BY_BITMASK(uint16_t, , 0x2000006e, 3, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000006f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000006f, 1, 7, 1);
+ *(uint16_t*)0x20000070 = 8;
+ *(uint16_t*)0x20000072 = 2;
+ *(uint32_t*)0x20000074 = 0xfffffffd;
+ *(uint16_t*)0x20000078 = 4;
+ *(uint16_t*)0x2000007a = 4;
+ *(uint16_t*)0x2000007c = 4;
+ *(uint16_t*)0x2000007e = 1;
+ *(uint64_t*)0x200001c8 = 0x40;
+ *(uint64_t*)0x20000258 = 1;
+ *(uint64_t*)0x20000260 = 0;
+ *(uint64_t*)0x20000268 = 0;
+ *(uint32_t*)0x20000270 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000240ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d25f08af566d1bbff3646aa29b49998d705d53e3.c b/syzkaller-repros/linux/d25f08af566d1bbff3646aa29b49998d705d53e3.c
new file mode 100644
index 0000000..fb8c1c9
--- /dev/null
+++ b/syzkaller-repros/linux/d25f08af566d1bbff3646aa29b49998d705d53e3.c
@@ -0,0 +1,137 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(long a0, long a1, long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ long res = 0;
+ memcpy((void*)0x20000480, "/dev/video#", 12);
+ res = syz_open_dev(0x20000480, 0x100000007fffffff, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000240 = 0;
+ *(uint32_t*)0x20000244 = 7;
+ *(uint32_t*)0x20000248 = 2;
+ *(uint32_t*)0x20000250 = 1;
+ *(uint16_t*)0x20000258 = 0;
+ *(uint16_t*)0x2000025a = 0;
+ *(uint16_t*)0x2000025c = 0;
+ *(uint16_t*)0x2000025e = 0;
+ *(uint16_t*)0x20000260 = 0;
+ *(uint16_t*)0x20000262 = 0;
+ *(uint16_t*)0x20000264 = 0;
+ *(uint16_t*)0x20000266 = 0;
+ *(uint16_t*)0x20000268 = 0;
+ *(uint16_t*)0x2000026a = 0;
+ *(uint16_t*)0x2000026c = 0;
+ *(uint16_t*)0x2000026e = 0x1000;
+ *(uint16_t*)0x20000270 = 0;
+ *(uint16_t*)0x20000272 = 0;
+ *(uint16_t*)0x20000274 = 0;
+ *(uint16_t*)0x20000276 = 0;
+ *(uint16_t*)0x20000278 = 0;
+ *(uint16_t*)0x2000027a = 0;
+ *(uint16_t*)0x2000027c = 0;
+ *(uint16_t*)0x2000027e = 0;
+ *(uint16_t*)0x20000280 = 0;
+ *(uint16_t*)0x20000282 = 0;
+ *(uint16_t*)0x20000284 = 0;
+ *(uint16_t*)0x20000286 = 0;
+ *(uint16_t*)0x20000288 = 0;
+ *(uint16_t*)0x2000028a = 0;
+ *(uint16_t*)0x2000028c = 0;
+ *(uint16_t*)0x2000028e = 0;
+ *(uint16_t*)0x20000290 = 0;
+ *(uint16_t*)0x20000292 = 0;
+ *(uint16_t*)0x20000294 = 0;
+ *(uint16_t*)0x20000296 = 0;
+ *(uint16_t*)0x20000298 = 0;
+ *(uint16_t*)0x2000029a = 0;
+ *(uint16_t*)0x2000029c = 0;
+ *(uint16_t*)0x2000029e = 0;
+ *(uint16_t*)0x200002a0 = 0;
+ *(uint16_t*)0x200002a2 = 0;
+ *(uint16_t*)0x200002a4 = 0;
+ *(uint16_t*)0x200002a6 = 0;
+ *(uint16_t*)0x200002a8 = 0;
+ *(uint16_t*)0x200002aa = 0;
+ *(uint16_t*)0x200002ac = 0;
+ *(uint16_t*)0x200002ae = 0;
+ *(uint16_t*)0x200002b0 = 0;
+ *(uint16_t*)0x200002b2 = 0;
+ *(uint16_t*)0x200002b4 = 0;
+ *(uint16_t*)0x200002b6 = 0;
+ *(uint16_t*)0x200002b8 = 0;
+ *(uint32_t*)0x200002bc = 0;
+ *(uint32_t*)0x200002c0 = 0;
+ *(uint32_t*)0x200002c4 = 0;
+ *(uint32_t*)0x20000320 = 0;
+ *(uint32_t*)0x20000324 = 0;
+ *(uint32_t*)0x20000328 = 0;
+ *(uint32_t*)0x2000032c = 0;
+ *(uint32_t*)0x20000330 = 0;
+ *(uint32_t*)0x20000334 = 0;
+ *(uint32_t*)0x20000338 = 0;
+ *(uint32_t*)0x2000033c = 0;
+ syscall(__NR_ioctl, r[0], 0xc100565c, 0x20000240);
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0x8000;
+ *(uint32_t*)0x200000c8 = 1;
+ *(uint32_t*)0x200000d0 = 1;
+ *(uint32_t*)0x200000d8 = 0;
+ *(uint32_t*)0x200000dc = 0;
+ *(uint32_t*)0x200000e0 = 0;
+ *(uint32_t*)0x200000e4 = 0;
+ *(uint32_t*)0x200000e8 = 0;
+ *(uint32_t*)0x200000ec = 0x15182c;
+ *(uint32_t*)0x200000f0 = 0;
+ *(uint32_t*)0x200000f4 = 0;
+ *(uint32_t*)0x200000f8 = 0;
+ *(uint32_t*)0x200000fc = 0;
+ *(uint32_t*)0x20000100 = 0;
+ *(uint32_t*)0x20000104 = 0;
+ *(uint32_t*)0x200001a0 = 0;
+ *(uint32_t*)0x200001a4 = 0;
+ *(uint32_t*)0x200001a8 = 0;
+ *(uint32_t*)0x200001ac = 0;
+ *(uint32_t*)0x200001b0 = 0;
+ *(uint32_t*)0x200001b4 = 0;
+ *(uint32_t*)0x200001b8 = 0;
+ *(uint32_t*)0x200001bc = 0;
+ syscall(__NR_ioctl, r[0], 0xc100565c, 0x200000c0);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d31813ba6b649194a2284b8e860326f1fe919d0c.c b/syzkaller-repros/linux/d31813ba6b649194a2284b8e860326f1fe919d0c.c
new file mode 100644
index 0000000..70ade6c
--- /dev/null
+++ b/syzkaller-repros/linux/d31813ba6b649194a2284b8e860326f1fe919d0c.c
@@ -0,0 +1,452 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 0x1e, 4, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ res = syscall(__NR_socket, 0x1e, 4, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 2:
+ *(uint32_t*)0x20000080 = 0x3fc;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ syscall(__NR_setsockopt, r[1], 0x10f, 0x87, 0x20000080, 0x10);
+ break;
+ case 3:
+ *(uint32_t*)0x20265000 = 0x3fc;
+ *(uint32_t*)0x20265004 = 0;
+ *(uint32_t*)0x20265008 = 0;
+ *(uint32_t*)0x2026500c = 0;
+ syscall(__NR_setsockopt, r[0], 0x10f, 0x87, 0x20265000, 0x10);
+ break;
+ case 4:
+ syscall(__NR_sendmmsg, r[0], 0x20000a40, 0x8000000000000b0, 0);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d42c5e0bf62a0373f9fe4ad941b5bcd8f48e79d8.c b/syzkaller-repros/linux/d42c5e0bf62a0373f9fe4ad941b5bcd8f48e79d8.c
new file mode 100644
index 0000000..3e020de
--- /dev/null
+++ b/syzkaller-repros/linux/d42c5e0bf62a0373f9fe4ad941b5bcd8f48e79d8.c
@@ -0,0 +1,494 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 6; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ *(uint32_t*)0x20000140 = 0xa;
+ *(uint32_t*)0x20000144 = 3;
+ *(uint32_t*)0x20000148 = 0x6c0d;
+ *(uint32_t*)0x2000014c = 1;
+ *(uint32_t*)0x20000150 = 2;
+ *(uint32_t*)0x20000154 = -1;
+ *(uint32_t*)0x20000158 = 0;
+ *(uint8_t*)0x2000015c = 0;
+ *(uint8_t*)0x2000015d = 0;
+ *(uint8_t*)0x2000015e = 0;
+ *(uint8_t*)0x2000015f = 0;
+ *(uint8_t*)0x20000160 = 0;
+ *(uint8_t*)0x20000161 = 0;
+ *(uint8_t*)0x20000162 = 0;
+ *(uint8_t*)0x20000163 = 0;
+ *(uint8_t*)0x20000164 = 0;
+ *(uint8_t*)0x20000165 = 0;
+ *(uint8_t*)0x20000166 = 0;
+ *(uint8_t*)0x20000167 = 0;
+ *(uint8_t*)0x20000168 = 0;
+ *(uint8_t*)0x20000169 = 0;
+ *(uint8_t*)0x2000016a = 0;
+ *(uint8_t*)0x2000016b = 0;
+ *(uint32_t*)0x2000016c = 0;
+ *(uint32_t*)0x20000170 = -1;
+ *(uint32_t*)0x20000174 = 0;
+ *(uint32_t*)0x20000178 = 0;
+ *(uint32_t*)0x2000017c = 0;
+ res = syscall(__NR_bpf, 0ul, 0x20000140ul, 0x3cul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint32_t*)0x20000180 = r[0];
+ *(uint64_t*)0x20000188 = 0x20000000;
+ *(uint64_t*)0x20000190 = 0x20000080;
+ *(uint64_t*)0x20000198 = 0;
+ syscall(__NR_bpf, 2ul, 0x20000180ul, 0x20ul);
+ break;
+ case 2:
+ syscall(__NR_bpf, 2ul, 0ul, 0ul);
+ break;
+ case 3:
+ *(uint32_t*)0x20fc7000 = 9;
+ *(uint32_t*)0x20fc7004 = 2;
+ *(uint32_t*)0x20fc7008 = 0x4a0f;
+ *(uint32_t*)0x20fc700c = 2;
+ *(uint32_t*)0x20fc7010 = 0;
+ *(uint32_t*)0x20fc7014 = -1;
+ *(uint32_t*)0x20fc7018 = 0;
+ *(uint8_t*)0x20fc701c = 0;
+ *(uint8_t*)0x20fc701d = 0;
+ *(uint8_t*)0x20fc701e = 0;
+ *(uint8_t*)0x20fc701f = 0;
+ *(uint8_t*)0x20fc7020 = 0;
+ *(uint8_t*)0x20fc7021 = 0;
+ *(uint8_t*)0x20fc7022 = 0;
+ *(uint8_t*)0x20fc7023 = 0;
+ *(uint8_t*)0x20fc7024 = 0;
+ *(uint8_t*)0x20fc7025 = 0;
+ *(uint8_t*)0x20fc7026 = 0;
+ *(uint8_t*)0x20fc7027 = 0;
+ *(uint8_t*)0x20fc7028 = 0;
+ *(uint8_t*)0x20fc7029 = 0;
+ *(uint8_t*)0x20fc702a = 0;
+ *(uint8_t*)0x20fc702b = 0;
+ *(uint32_t*)0x20fc702c = 0;
+ *(uint32_t*)0x20fc7030 = -1;
+ *(uint32_t*)0x20fc7034 = 0;
+ *(uint32_t*)0x20fc7038 = 0;
+ *(uint32_t*)0x20fc703c = 0;
+ res = syscall(__NR_bpf, 0ul, 0x20fc7000ul, 0x40ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 4:
+ *(uint32_t*)0x20000000 = r[1];
+ *(uint64_t*)0x20000008 = 0x20fcbfff;
+ *(uint64_t*)0x20000010 = 0x20172000;
+ *(uint64_t*)0x20000018 = 0;
+ syscall(__NR_bpf, 2ul, 0x20000000ul, 0x20ul);
+ break;
+ case 5:
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint64_t*)0x200001c8 = 0;
+ *(uint64_t*)0x200001d0 = 0;
+ *(uint64_t*)0x200001d8 = 0;
+ *(uint32_t*)0x200001e0 = 6;
+ *(uint32_t*)0x200001e4 = r[1];
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint64_t*)0x200001f0 = 0;
+ syscall(__NR_bpf, 0x19ul, 0x200001c0ul, 0x38ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d50415e7b7b96bf0167377b93aa5ab497e534a27.c b/syzkaller-repros/linux/d50415e7b7b96bf0167377b93aa5ab497e534a27.c
new file mode 100644
index 0000000..eab34b8
--- /dev/null
+++ b/syzkaller-repros/linux/d50415e7b7b96bf0167377b93aa5ab497e534a27.c
@@ -0,0 +1,58 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x4b3aul, 1ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x20000240 = 0xfff;
+ *(uint16_t*)0x20000242 = 9;
+ *(uint16_t*)0x20000244 = 0x100;
+ syscall(__NR_ioctl, r[1], 0x5609ul, 0x20000240ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[2] = res;
+ syscall(__NR_ioctl, r[2], 0x4b3aul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d5b4a3660a50244c4ff02f404c21e30f54f86c06.c b/syzkaller-repros/linux/d5b4a3660a50244c4ff02f404c21e30f54f86c06.c
new file mode 100644
index 0000000..c9087e5
--- /dev/null
+++ b/syzkaller-repros/linux/d5b4a3660a50244c4ff02f404c21e30f54f86c06.c
@@ -0,0 +1,107 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ intptr_t res = 0;
+ NONFAILING(memcpy((void*)0x20000080, "/dev/i2c-#\000", 11));
+ res = syz_open_dev(0x20000080, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ NONFAILING(*(uint8_t*)0x20000040 = 0);
+ NONFAILING(*(uint8_t*)0x20000041 = 0);
+ NONFAILING(*(uint32_t*)0x20000044 = 5);
+ NONFAILING(*(uint64_t*)0x20000048 = 0);
+ syscall(__NR_ioctl, r[0], 0x702ul, 0x20000040ul);
+ res = syz_open_dev(0, 0, 0);
+ if (res != -1)
+ r[1] = res;
+ NONFAILING(*(uint8_t*)0x20000040 = 0);
+ NONFAILING(*(uint8_t*)0x20000041 = 0);
+ NONFAILING(*(uint32_t*)0x20000044 = 6);
+ NONFAILING(*(uint64_t*)0x20000048 = 0x20000000);
+ NONFAILING(*(uint8_t*)0x20000000 = 0x21);
+ NONFAILING(memcpy(
+ (void*)0x20000001,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xff\xff\xff\xff\xff\xff\xff\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 33));
+ syscall(__NR_ioctl, r[1], 0x720ul, 0x20000040ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d67643a91b624d26806fec135662c57038a4eda7.c b/syzkaller-repros/linux/d67643a91b624d26806fec135662c57038a4eda7.c
new file mode 100644
index 0000000..cf3dabe
--- /dev/null
+++ b/syzkaller-repros/linux/d67643a91b624d26806fec135662c57038a4eda7.c
@@ -0,0 +1,123 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x20000000;
+ *(uint64_t*)0x20000000 = 0x20000040;
+ *(uint32_t*)0x20000040 = 0x54;
+ *(uint8_t*)0x20000044 = 2;
+ *(uint8_t*)0x20000045 = 6;
+ *(uint16_t*)0x20000046 = 1;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint8_t*)0x20000050 = 7;
+ *(uint8_t*)0x20000051 = 0;
+ *(uint16_t*)0x20000052 = htobe16(0);
+ *(uint16_t*)0x20000054 = 0xd;
+ *(uint16_t*)0x20000056 = 3;
+ memcpy((void*)0x20000058, "hash:net\000", 9);
+ *(uint16_t*)0x20000064 = 9;
+ *(uint16_t*)0x20000066 = 2;
+ memcpy((void*)0x20000068, "syz2\000", 5);
+ *(uint16_t*)0x20000070 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000072, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000073, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000073, 1, 7, 1);
+ *(uint16_t*)0x20000074 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000076, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000077, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000077, 0, 7, 1);
+ *(uint32_t*)0x20000078 = htobe32(0x3b);
+ *(uint16_t*)0x2000007c = 5;
+ *(uint16_t*)0x2000007e = 1;
+ *(uint8_t*)0x20000080 = 7;
+ *(uint16_t*)0x20000084 = 5;
+ *(uint16_t*)0x20000086 = 4;
+ *(uint8_t*)0x20000088 = 0;
+ *(uint16_t*)0x2000008c = 5;
+ *(uint16_t*)0x2000008e = 5;
+ *(uint8_t*)0x20000090 = 2;
+ *(uint64_t*)0x20000008 = 0x54;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0x20000040;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000d00 = 0;
+ *(uint32_t*)0x20000d08 = 0;
+ *(uint64_t*)0x20000d10 = 0x20000cc0;
+ *(uint64_t*)0x20000cc0 = 0x20000080;
+ *(uint32_t*)0x20000080 = 0x44;
+ *(uint8_t*)0x20000084 = 9;
+ *(uint8_t*)0x20000085 = 6;
+ *(uint16_t*)0x20000086 = 0x801;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint32_t*)0x2000008c = 0;
+ *(uint8_t*)0x20000090 = 0;
+ *(uint8_t*)0x20000091 = 0;
+ *(uint16_t*)0x20000092 = htobe16(0);
+ *(uint16_t*)0x20000094 = 5;
+ *(uint16_t*)0x20000096 = 1;
+ *(uint8_t*)0x20000098 = 7;
+ *(uint16_t*)0x2000009c = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x2000009e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000009f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000009f, 1, 7, 1);
+ *(uint16_t*)0x200000a0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000a2, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000a3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000a3, 1, 7, 1);
+ *(uint16_t*)0x200000a4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000a6, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000a7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000a7, 0, 7, 1);
+ *(uint32_t*)0x200000a8 = htobe32(0xc6);
+ *(uint16_t*)0x200000ac = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000ae, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000af, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000af, 1, 7, 1);
+ *(uint16_t*)0x200000b0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000b2, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000b3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000b3, 0, 7, 1);
+ *(uint32_t*)0x200000b4 = htobe32(0xe0000001);
+ *(uint16_t*)0x200000b8 = 9;
+ *(uint16_t*)0x200000ba = 2;
+ memcpy((void*)0x200000bc, "syz2\000", 5);
+ *(uint64_t*)0x20000cc8 = 0x44;
+ *(uint64_t*)0x20000d18 = 1;
+ *(uint64_t*)0x20000d20 = 0;
+ *(uint64_t*)0x20000d28 = 0;
+ *(uint32_t*)0x20000d30 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000d00ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d678bac282884bdebf54dcba95f494209d35c4ac.c b/syzkaller-repros/linux/d678bac282884bdebf54dcba95f494209d35c4ac.c
new file mode 100644
index 0000000..a081e00
--- /dev/null
+++ b/syzkaller-repros/linux/d678bac282884bdebf54dcba95f494209d35c4ac.c
@@ -0,0 +1,92 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ intptr_t res = 0;
+ syscall(__NR_perf_event_open, 0ul, 0, 0ul, -1, 0ul);
+ memcpy((void*)0x200001c0, "/dev/ptmx\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200001c0ul, 2ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x20000040, "\xe0", 1);
+ inject_fault(2);
+ syscall(__NR_write, r[0], 0x20000040ul, 0xfffffe00ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d83b8c5a988c2fb1aa02dca97af8e4db823f0429.c b/syzkaller-repros/linux/d83b8c5a988c2fb1aa02dca97af8e4db823f0429.c
new file mode 100644
index 0000000..1d39239
--- /dev/null
+++ b/syzkaller-repros/linux/d83b8c5a988c2fb1aa02dca97af8e4db823f0429.c
@@ -0,0 +1,442 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+#ifndef __NR_memfd_create
+#define __NR_memfd_create 319
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_memfd_create, 0ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0ul);
+ syscall(__NR_perf_event_open, 0ul, 0, -1ul, -1, 0ul);
+ syscall(__NR_lsetxattr, 0ul, 0ul, 0ul, 0ul, 0ul);
+ memcpy((void*)0x20000000, "/dev/ptmx\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000080 = 0x15;
+ inject_fault(10);
+ syscall(__NR_ioctl, r[0], 0x5423ul, 0x20000080ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/d9776b55c9e677e21256ad05a2a157806e4d79c7.c b/syzkaller-repros/linux/d9776b55c9e677e21256ad05a2a157806e4d79c7.c
new file mode 100644
index 0000000..ff09935
--- /dev/null
+++ b/syzkaller-repros/linux/d9776b55c9e677e21256ad05a2a157806e4d79c7.c
@@ -0,0 +1,245 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000440;
+ *(uint32_t*)0x20000440 = 0x50;
+ *(uint8_t*)0x20000444 = 2;
+ *(uint8_t*)0x20000445 = 6;
+ *(uint16_t*)0x20000446 = 1;
+ *(uint32_t*)0x20000448 = 0;
+ *(uint32_t*)0x2000044c = 0;
+ *(uint8_t*)0x20000450 = 0;
+ *(uint8_t*)0x20000451 = 3;
+ *(uint16_t*)0x20000452 = htobe16(0);
+ *(uint16_t*)0x20000454 = 9;
+ *(uint16_t*)0x20000456 = 2;
+ memcpy((void*)0x20000458, "syz2\000", 5);
+ *(uint16_t*)0x20000460 = 0xc;
+ *(uint16_t*)0x20000462 = 3;
+ memcpy((void*)0x20000464, "hash:ip\000", 8);
+ *(uint16_t*)0x2000046c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000046e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000046f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000046f, 1, 7, 1);
+ *(uint16_t*)0x20000470 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000472, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 0, 7, 1);
+ *(uint32_t*)0x20000474 = htobe32(0);
+ *(uint16_t*)0x20000478 = 5;
+ *(uint16_t*)0x2000047a = 1;
+ *(uint8_t*)0x2000047c = 7;
+ *(uint16_t*)0x20000480 = 5;
+ *(uint16_t*)0x20000482 = 4;
+ *(uint8_t*)0x20000484 = 0;
+ *(uint16_t*)0x20000488 = 5;
+ *(uint16_t*)0x2000048a = 5;
+ *(uint8_t*)0x2000048c = 2;
+ *(uint64_t*)0x200002c8 = 0x50;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0x200000000000000;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000d00 = 0;
+ *(uint32_t*)0x20000d08 = 0;
+ *(uint64_t*)0x20000d10 = 0x20000cc0;
+ *(uint64_t*)0x20000cc0 = 0x20000180;
+ *(uint32_t*)0x20000180 = 0x44;
+ *(uint8_t*)0x20000184 = 9;
+ *(uint8_t*)0x20000185 = 6;
+ *(uint16_t*)0x20000186 = 0x801;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint32_t*)0x2000018c = 0;
+ *(uint8_t*)0x20000190 = 0;
+ *(uint8_t*)0x20000191 = 0;
+ *(uint16_t*)0x20000192 = htobe16(0);
+ *(uint16_t*)0x20000194 = 5;
+ *(uint16_t*)0x20000196 = 1;
+ *(uint8_t*)0x20000198 = 7;
+ *(uint16_t*)0x2000019c = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x2000019e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019f, 1, 7, 1);
+ *(uint16_t*)0x200001a0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001a2, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 1, 7, 1);
+ *(uint16_t*)0x200001a4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001a6, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a7, 0, 7, 1);
+ *(uint32_t*)0x200001a8 = htobe32(0);
+ *(uint16_t*)0x200001ac = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ae, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001af, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001af, 1, 7, 1);
+ *(uint16_t*)0x200001b0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001b2, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001b3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001b3, 0, 7, 1);
+ *(uint32_t*)0x200001b4 = htobe32(0xe0000001);
+ *(uint16_t*)0x200001b8 = 9;
+ *(uint16_t*)0x200001ba = 2;
+ memcpy((void*)0x200001bc, "syz2\000", 5);
+ *(uint64_t*)0x20000cc8 = 0x44;
+ *(uint64_t*)0x20000d18 = 1;
+ *(uint64_t*)0x20000d20 = 0;
+ *(uint64_t*)0x20000d28 = 0;
+ *(uint32_t*)0x20000d30 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000d00ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/dadeca0bd04f4d6328cfe8197796f6bb71ee9594.c b/syzkaller-repros/linux/dadeca0bd04f4d6328cfe8197796f6bb71ee9594.c
new file mode 100644
index 0000000..16b3ea9
--- /dev/null
+++ b/syzkaller-repros/linux/dadeca0bd04f4d6328cfe8197796f6bb71ee9594.c
@@ -0,0 +1,767 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ loop();
+ exit(1);
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 8; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0x0};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ syscall(__NR_perf_event_open, 0ul, 0, 0ul, -1, 0ul);
+ break;
+ case 1:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 4:
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint64_t*)0x200001d0 = 0x20000180;
+ *(uint64_t*)0x20000180 = 0;
+ *(uint64_t*)0x20000188 = 0;
+ *(uint64_t*)0x200001d8 = 1;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001f0 = 0;
+ syscall(__NR_sendmsg, r[2], 0x200001c0ul, 0ul);
+ break;
+ case 5:
+ *(uint32_t*)0x20000200 = 0x14;
+ res = syscall(__NR_getsockname, r[2], 0x20000100ul, 0x20000200ul);
+ if (res != -1)
+ r[3] = *(uint32_t*)0x20000104;
+ break;
+ case 6:
+ *(uint64_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint64_t*)0x20000050 = 0x20000000;
+ *(uint64_t*)0x20000000 = 0x20000340;
+ memcpy((void*)0x20000340,
+ "\x48\x00\x00\x00\x10\x00\x05\x07\xe4\xff\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ 20);
+ *(uint32_t*)0x20000354 = r[3];
+ memcpy((void*)0x20000358,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x12\x00\x0c\x00\x01\x00"
+ "\x76\x65\x74\x68\x00\x00\x00\x00\x18\x00\x02\x00\x14\x00\x01\x00"
+ "\x00\x00\x00\x00",
+ 36);
+ *(uint32_t*)0x2000037c = 0;
+ memcpy((void*)0x20000380,
+ "\x00\x2d\xdd\x8b\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\xb7\x8c\x84\xdc\xb7\xbf\x85\x6c\x1f\x0a\x2d\xea\x84\x80\x6c"
+ "\xe2\x6c\xdb\xd4\xc5\x1d\x40\x82\x1a\xca\x93\x20\xa5\x14\x91\x97"
+ "\xcb\x98\xe2\x27\x06\xb0\xc1\x15\xfb\xc7\xf7\xa9\x7d\xc5\xc4\x27"
+ "\x60\xad\x10\x4d\x77\xc9\xc5\x73\xc6\xc0\x07\x99\x2e\xf1\xd2\x00"
+ "\x3d\xfc\xcc\x3f\x1a\x59\x81\x57\x8f\x6e\x14\x58\xf0\x93\x6b\xea"
+ "\x28\x04\xff\xea\x72\x23\x18\x24\x51\x81\xa4\x4a\x49\x33\xc3",
+ 111);
+ *(uint64_t*)0x20000008 = 0x48;
+ *(uint64_t*)0x20000058 = 1;
+ *(uint64_t*)0x20000060 = 0;
+ *(uint64_t*)0x20000068 = 0;
+ *(uint32_t*)0x20000070 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000040ul, 0ul);
+ break;
+ case 7:
+ *(uint64_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000088 = 0;
+ *(uint64_t*)0x20000090 = 0x20000040;
+ *(uint64_t*)0x20000040 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x28;
+ *(uint16_t*)0x20000004 = 0x10;
+ *(uint16_t*)0x20000006 = 0x801;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint8_t*)0x20000010 = 0;
+ *(uint8_t*)0x20000011 = 0;
+ *(uint16_t*)0x20000012 = 0;
+ *(uint32_t*)0x20000014 = r[3];
+ *(uint32_t*)0x20000018 = 0;
+ *(uint32_t*)0x2000001c = 0;
+ *(uint16_t*)0x20000020 = 8;
+ *(uint16_t*)0x20000022 = 0x1c;
+ *(uint8_t*)0x20000024 = 0xef;
+ *(uint64_t*)0x20000048 = 0x28;
+ *(uint64_t*)0x20000098 = 1;
+ *(uint64_t*)0x200000a0 = 0;
+ *(uint64_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000b0 = 0;
+ inject_fault(22);
+ syscall(__NR_sendmsg, r[0], 0x20000080ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/db5c0b369f0a94927e3d09cefcccf8871898b64b.c b/syzkaller-repros/linux/db5c0b369f0a94927e3d09cefcccf8871898b64b.c
new file mode 100644
index 0000000..835238b
--- /dev/null
+++ b/syzkaller-repros/linux/db5c0b369f0a94927e3d09cefcccf8871898b64b.c
@@ -0,0 +1,34 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+const int kInitNetNsFd = 239;
+
+static long syz_init_net_socket(volatile long domain, volatile long type,
+ volatile long proto)
+{
+ return syscall(__NR_socket, domain, type, proto);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_init_net_socket(0x1f, 5, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000080 = 0;
+ syscall(__NR_getsockopt, r[0], 0x112ul, 0xeul, 0ul, 0x20000080ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/dc6d400c372e699f23dcc717591d6b66152a6dba.c b/syzkaller-repros/linux/dc6d400c372e699f23dcc717591d6b66152a6dba.c
new file mode 100644
index 0000000..3183908
--- /dev/null
+++ b/syzkaller-repros/linux/dc6d400c372e699f23dcc717591d6b66152a6dba.c
@@ -0,0 +1,1521 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ exit(1);
+ if (chmod(tmpdir, 0777))
+ exit(1);
+ if (chdir(tmpdir))
+ exit(1);
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
+ const void* addr, int addrsize, const void* mac,
+ int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, NDA_DST, addr, addrsize);
+ netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+ &macaddr, ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+ &macaddr, ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+ NULL);
+ close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[1000];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ while (umount2(dir, MNT_DETACH) == 0) {
+ }
+ dp = opendir(dir);
+ if (dp == NULL) {
+ if (errno == EMFILE) {
+ exit(1);
+ }
+ exit(1);
+ }
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ while (umount2(filename, MNT_DETACH) == 0) {
+ }
+ struct stat st;
+ if (lstat(filename, &st))
+ exit(1);
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EPERM) {
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno != EBUSY || i > 100)
+ exit(1);
+ if (umount2(filename, MNT_DETACH))
+ exit(1);
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EPERM) {
+ int fd = open(dir, O_RDONLY);
+ if (fd != -1) {
+ long flags = 0;
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
+ }
+ close(fd);
+ continue;
+ }
+ }
+ if (errno == EROFS) {
+ break;
+ }
+ if (errno == EBUSY) {
+ if (umount2(dir, MNT_DETACH))
+ exit(1);
+ continue;
+ }
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ exit(1);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 3; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ char cwdbuf[32];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ exit(1);
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ if (chdir(cwdbuf))
+ exit(1);
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ remove_dir(cwdbuf);
+ }
+}
+
+#ifndef __NR_io_uring_register
+#define __NR_io_uring_register 427
+#endif
+#ifndef __NR_io_uring_setup
+#define __NR_io_uring_setup 425
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ NONFAILING(*(uint32_t*)0x2001d000 = 1);
+ NONFAILING(*(uint32_t*)0x2001d004 = 0x70);
+ NONFAILING(*(uint8_t*)0x2001d008 = 0);
+ NONFAILING(*(uint8_t*)0x2001d009 = 0);
+ NONFAILING(*(uint8_t*)0x2001d00a = 0);
+ NONFAILING(*(uint8_t*)0x2001d00b = 0);
+ NONFAILING(*(uint32_t*)0x2001d00c = 0);
+ NONFAILING(*(uint64_t*)0x2001d010 = 0x41c1);
+ NONFAILING(*(uint64_t*)0x2001d018 = 0);
+ NONFAILING(*(uint64_t*)0x2001d020 = 0);
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 0, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 1, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 2, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 3, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 4, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 3, 5, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 6, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 7, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 8, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 9, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 10, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 11, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 12, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 13, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 14, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 15, 2));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 17, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 18, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 19, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 20, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 21, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 22, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 23, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 24, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 25, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 26, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 27, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 28, 1));
+ NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 29, 35));
+ NONFAILING(*(uint32_t*)0x2001d030 = 0);
+ NONFAILING(*(uint32_t*)0x2001d034 = 0);
+ NONFAILING(*(uint64_t*)0x2001d038 = 0);
+ NONFAILING(*(uint64_t*)0x2001d040 = 0);
+ NONFAILING(*(uint64_t*)0x2001d048 = 0);
+ NONFAILING(*(uint64_t*)0x2001d050 = 0);
+ NONFAILING(*(uint32_t*)0x2001d058 = 0);
+ NONFAILING(*(uint32_t*)0x2001d05c = 0);
+ NONFAILING(*(uint64_t*)0x2001d060 = 0);
+ NONFAILING(*(uint32_t*)0x2001d068 = 0);
+ NONFAILING(*(uint16_t*)0x2001d06c = 0);
+ NONFAILING(*(uint16_t*)0x2001d06e = 0);
+ syscall(__NR_perf_event_open, 0x2001d000ul, 0, -1ul, -1, 0ul);
+ break;
+ case 1:
+ NONFAILING(*(uint32_t*)0x20000080 = 0);
+ NONFAILING(*(uint32_t*)0x20000084 = 0);
+ NONFAILING(*(uint32_t*)0x20000088 = 0);
+ NONFAILING(*(uint32_t*)0x2000008c = 0);
+ NONFAILING(*(uint32_t*)0x20000090 = 0);
+ NONFAILING(*(uint32_t*)0x20000094 = 0);
+ NONFAILING(*(uint32_t*)0x20000098 = 0);
+ NONFAILING(*(uint32_t*)0x2000009c = 0);
+ NONFAILING(*(uint32_t*)0x200000a0 = 0);
+ NONFAILING(*(uint32_t*)0x200000a4 = 0);
+ NONFAILING(*(uint32_t*)0x200000a8 = 0);
+ NONFAILING(*(uint32_t*)0x200000ac = 0);
+ NONFAILING(*(uint32_t*)0x200000b0 = 0);
+ NONFAILING(*(uint32_t*)0x200000b4 = 0);
+ NONFAILING(*(uint32_t*)0x200000b8 = 0);
+ NONFAILING(*(uint32_t*)0x200000bc = 0);
+ NONFAILING(*(uint32_t*)0x200000c0 = 0);
+ NONFAILING(*(uint32_t*)0x200000c4 = 0);
+ NONFAILING(*(uint64_t*)0x200000c8 = 0);
+ NONFAILING(*(uint32_t*)0x200000d0 = 0);
+ NONFAILING(*(uint32_t*)0x200000d4 = 0);
+ NONFAILING(*(uint32_t*)0x200000d8 = 0);
+ NONFAILING(*(uint32_t*)0x200000dc = 0);
+ NONFAILING(*(uint32_t*)0x200000e0 = 0);
+ NONFAILING(*(uint32_t*)0x200000e4 = 0);
+ NONFAILING(*(uint32_t*)0x200000e8 = 0);
+ NONFAILING(*(uint32_t*)0x200000ec = 0);
+ NONFAILING(*(uint64_t*)0x200000f0 = 0);
+ res = syscall(__NR_io_uring_setup, 0xa4, 0x20000080ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 2:
+ NONFAILING(*(uint32_t*)0x20000280 = -1);
+ syscall(__NR_io_uring_register, r[0], 2ul, 0x20000280ul, 1ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_binfmt_misc();
+ install_segv_handler();
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ use_temporary_dir();
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e02d0c83bf477ef195f4080ed7c0339a86b10f27.c b/syzkaller-repros/linux/e02d0c83bf477ef195f4080ed7c0339a86b10f27.c
new file mode 100644
index 0000000..bdb70b3
--- /dev/null
+++ b/syzkaller-repros/linux/e02d0c83bf477ef195f4080ed7c0339a86b10f27.c
@@ -0,0 +1,28 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000100, "/dev/ptmx\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000100, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x200000c0 = 0xf;
+ syscall(__NR_ioctl, r[0], 0x5423, 0x200000c0);
+ syscall(__NR_ioctl, r[0], 0x400455c8, 8);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e07ae74f38e943b1838e053e3204b480235c6b31.c b/syzkaller-repros/linux/e07ae74f38e943b1838e053e3204b480235c6b31.c
new file mode 100644
index 0000000..d8edf67
--- /dev/null
+++ b/syzkaller-repros/linux/e07ae74f38e943b1838e053e3204b480235c6b31.c
@@ -0,0 +1,198 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+void execute_one(void)
+{
+ *(uint32_t*)0x20000180 = 0;
+ *(uint32_t*)0x20000184 = 0x70;
+ *(uint8_t*)0x20000188 = 3;
+ *(uint8_t*)0x20000189 = 0;
+ *(uint8_t*)0x2000018a = 0;
+ *(uint8_t*)0x2000018b = 0;
+ *(uint32_t*)0x2000018c = 0;
+ *(uint64_t*)0x20000190 = 6;
+ *(uint64_t*)0x20000198 = 0xa0;
+ *(uint64_t*)0x200001a0 = 0;
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 0, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 1, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 2, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 3, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 4, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 5, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 6, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 7, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 8, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 9, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 10, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 11, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 12, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 13, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 14, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 15, 2);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 17, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 18, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 19, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 20, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 21, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 22, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 23, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 24, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 25, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 26, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 27, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 28, 1);
+ STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 29, 35);
+ *(uint32_t*)0x200001b0 = 0;
+ *(uint32_t*)0x200001b4 = 0;
+ *(uint64_t*)0x200001b8 = 0;
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint64_t*)0x200001c8 = 0x23;
+ *(uint64_t*)0x200001d0 = 0;
+ *(uint32_t*)0x200001d8 = 0;
+ *(uint32_t*)0x200001dc = 0;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint32_t*)0x200001e8 = 0;
+ *(uint16_t*)0x200001ec = 0;
+ *(uint16_t*)0x200001ee = 0;
+ syscall(__NR_perf_event_open, 0x20000180ul, 0, -1ul, -1, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e24f0807cf78061bdbe5e9ca08df641fe4f33126.c b/syzkaller-repros/linux/e24f0807cf78061bdbe5e9ca08df641fe4f33126.c
new file mode 100644
index 0000000..b1644c4
--- /dev/null
+++ b/syzkaller-repros/linux/e24f0807cf78061bdbe5e9ca08df641fe4f33126.c
@@ -0,0 +1,241 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20001080 = 0;
+ *(uint32_t*)0x20001088 = 0;
+ *(uint64_t*)0x20001090 = 0x20001040;
+ *(uint64_t*)0x20001040 = 0x20000f80;
+ *(uint32_t*)0x20000f80 = 0x48;
+ *(uint8_t*)0x20000f84 = 2;
+ *(uint8_t*)0x20000f85 = 6;
+ *(uint16_t*)0x20000f86 = 0x201;
+ *(uint32_t*)0x20000f88 = 0;
+ *(uint32_t*)0x20000f8c = 0;
+ *(uint8_t*)0x20000f90 = 0;
+ *(uint8_t*)0x20000f91 = 0;
+ *(uint16_t*)0x20000f92 = htobe16(0);
+ *(uint16_t*)0x20000f94 = 0xd;
+ *(uint16_t*)0x20000f96 = 3;
+ memcpy((void*)0x20000f98, "hash:mac\000", 9);
+ *(uint16_t*)0x20000fa4 = 5;
+ *(uint16_t*)0x20000fa6 = 4;
+ *(uint8_t*)0x20000fa8 = 0;
+ *(uint16_t*)0x20000fac = 9;
+ *(uint16_t*)0x20000fae = 2;
+ memcpy((void*)0x20000fb0, "syz1\000", 5);
+ *(uint16_t*)0x20000fb8 = 5;
+ *(uint16_t*)0x20000fba = 5;
+ *(uint8_t*)0x20000fbc = 0;
+ *(uint16_t*)0x20000fc0 = 5;
+ *(uint16_t*)0x20000fc2 = 1;
+ *(uint8_t*)0x20000fc4 = 7;
+ *(uint64_t*)0x20001048 = 0x48;
+ *(uint64_t*)0x20001098 = 1;
+ *(uint64_t*)0x200010a0 = 0;
+ *(uint64_t*)0x200010a8 = 0;
+ *(uint32_t*)0x200010b0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20001080ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x200001c0 = 0;
+ *(uint32_t*)0x200001c8 = 0;
+ *(uint64_t*)0x200001d0 = 0x20000180;
+ *(uint64_t*)0x20000180 = 0x20000040;
+ *(uint32_t*)0x20000040 = 0x114;
+ *(uint8_t*)0x20000044 = 0xb;
+ *(uint8_t*)0x20000045 = 6;
+ *(uint16_t*)0x20000046 = 5;
+ *(uint32_t*)0x20000048 = 0x70bd28;
+ *(uint32_t*)0x2000004c = 0x25dfdbfd;
+ *(uint8_t*)0x20000050 = 0;
+ *(uint8_t*)0x20000051 = 0;
+ *(uint16_t*)0x20000052 = htobe16(7);
+ *(uint16_t*)0x20000054 = 9;
+ *(uint16_t*)0x20000056 = 2;
+ memcpy((void*)0x20000058, "syz2\000", 5);
+ *(uint16_t*)0x20000060 = 5;
+ *(uint16_t*)0x20000062 = 1;
+ *(uint8_t*)0x20000064 = 7;
+ *(uint16_t*)0x20000068 = 0xa0;
+ STORE_BY_BITMASK(uint16_t, , 0x2000006a, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000006b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000006b, 1, 7, 1);
+ *(uint16_t*)0x2000006c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000006e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000006f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000006f, 1, 7, 1);
+ *(uint16_t*)0x20000070 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000072, 0xb, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000073, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000073, 0, 7, 1);
+ *(uint32_t*)0x20000074 = htobe32(1);
+ *(uint16_t*)0x20000078 = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x2000007a, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000007b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000007b, 1, 7, 1);
+ *(uint16_t*)0x2000007c = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x2000007e, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000007f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000007f, 1, 7, 1);
+ *(uint16_t*)0x20000080 = 0x14;
+ *(uint16_t*)0x20000082 = 2;
+ *(uint8_t*)0x20000084 = 0xfe;
+ *(uint8_t*)0x20000085 = 0x80;
+ *(uint8_t*)0x20000086 = 0;
+ *(uint8_t*)0x20000087 = 0;
+ *(uint8_t*)0x20000088 = 0;
+ *(uint8_t*)0x20000089 = 0;
+ *(uint8_t*)0x2000008a = 0;
+ *(uint8_t*)0x2000008b = 0;
+ *(uint8_t*)0x2000008c = 0;
+ *(uint8_t*)0x2000008d = 0;
+ *(uint8_t*)0x2000008e = 0;
+ *(uint8_t*)0x2000008f = 0;
+ *(uint8_t*)0x20000090 = 0;
+ *(uint8_t*)0x20000091 = 0;
+ *(uint8_t*)0x20000092 = 0;
+ *(uint8_t*)0x20000093 = 0xaa;
+ *(uint16_t*)0x20000094 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x20000096, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000097, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000097, 1, 7, 1);
+ *(uint16_t*)0x20000098 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000009a, 0x1b, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000009b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000009b, 0, 7, 1);
+ *(uint64_t*)0x2000009c = htobe64(3);
+ *(uint16_t*)0x200000a4 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000a6, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000a7, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000a7, 1, 7, 1);
+ *(uint16_t*)0x200000a8 = 5;
+ *(uint16_t*)0x200000aa = 7;
+ *(uint8_t*)0x200000ac = 0x73;
+ *(uint16_t*)0x200000b0 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x200000b2, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000b3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000b3, 1, 7, 1);
+ *(uint16_t*)0x200000b4 = 0xa;
+ *(uint16_t*)0x200000b6 = 0x11;
+ *(uint8_t*)0x200000b8 = 1;
+ *(uint8_t*)0x200000b9 = 0x80;
+ *(uint8_t*)0x200000ba = 0xc2;
+ *(uint8_t*)0x200000bb = 0;
+ *(uint8_t*)0x200000bc = 0;
+ *(uint8_t*)0x200000bd = 3;
+ *(uint16_t*)0x200000c0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000c2, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000c3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000c3, 1, 7, 1);
+ *(uint16_t*)0x200000c4 = 5;
+ *(uint16_t*)0x200000c6 = 7;
+ *(uint8_t*)0x200000c8 = 1;
+ *(uint16_t*)0x200000cc = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x200000ce, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000cf, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000cf, 1, 7, 1);
+ *(uint16_t*)0x200000d0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000d2, 0x1b, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000d3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000d3, 0, 7, 1);
+ *(uint64_t*)0x200000d4 = htobe64(0x20);
+ *(uint16_t*)0x200000dc = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200000de, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000df, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000df, 1, 7, 1);
+ *(uint16_t*)0x200000e0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200000e2, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000e3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000e3, 0, 7, 1);
+ *(uint32_t*)0x200000e4 = htobe32(0x101);
+ *(uint16_t*)0x200000e8 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x200000ea, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000eb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000eb, 1, 7, 1);
+ *(uint16_t*)0x200000ec = 0xa;
+ *(uint16_t*)0x200000ee = 0x11;
+ *(uint8_t*)0x200000f0 = -1;
+ *(uint8_t*)0x200000f1 = -1;
+ *(uint8_t*)0x200000f2 = -1;
+ *(uint8_t*)0x200000f3 = -1;
+ *(uint8_t*)0x200000f4 = -1;
+ *(uint8_t*)0x200000f5 = -1;
+ *(uint16_t*)0x200000f8 = 0x10;
+ STORE_BY_BITMASK(uint16_t, , 0x200000fa, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200000fb, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200000fb, 1, 7, 1);
+ *(uint16_t*)0x200000fc = 0xa;
+ *(uint16_t*)0x200000fe = 0x11;
+ *(uint8_t*)0x20000100 = 1;
+ *(uint8_t*)0x20000101 = 0x80;
+ *(uint8_t*)0x20000102 = 0xc2;
+ *(uint8_t*)0x20000103 = 0;
+ *(uint8_t*)0x20000104 = 0;
+ *(uint8_t*)0x20000105 = 1;
+ *(uint16_t*)0x20000108 = 9;
+ *(uint16_t*)0x2000010a = 2;
+ memcpy((void*)0x2000010c, "syz2\000", 5);
+ *(uint16_t*)0x20000114 = 5;
+ *(uint16_t*)0x20000116 = 1;
+ *(uint8_t*)0x20000118 = 7;
+ *(uint16_t*)0x2000011c = 9;
+ *(uint16_t*)0x2000011e = 2;
+ memcpy((void*)0x20000120, "syz1\000", 5);
+ *(uint16_t*)0x20000128 = 0x2c;
+ STORE_BY_BITMASK(uint16_t, , 0x2000012a, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000012b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000012b, 1, 7, 1);
+ *(uint16_t*)0x2000012c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000012e, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000012f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000012f, 0, 7, 1);
+ *(uint32_t*)0x20000130 = htobe32(0xee);
+ *(uint16_t*)0x20000134 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000136, 0x1b, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000137, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000137, 0, 7, 1);
+ *(uint64_t*)0x20000138 = htobe64(0xac);
+ *(uint16_t*)0x20000140 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000142, 9, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000143, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000143, 0, 7, 1);
+ *(uint32_t*)0x20000144 = htobe32(8);
+ *(uint16_t*)0x20000148 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000014a, 0x1b, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000014b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000014b, 0, 7, 1);
+ *(uint64_t*)0x2000014c = htobe64(5);
+ *(uint64_t*)0x20000188 = 0x114;
+ *(uint64_t*)0x200001d8 = 1;
+ *(uint64_t*)0x200001e0 = 0;
+ *(uint64_t*)0x200001e8 = 0;
+ *(uint32_t*)0x200001f0 = 0x4000;
+ syscall(__NR_sendmsg, r[1], 0x200001c0ul, 0x800ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e4432806b1b9c791b6c3185785fcdbdcd8054d4f.c b/syzkaller-repros/linux/e4432806b1b9c791b6c3185785fcdbdcd8054d4f.c
new file mode 100644
index 0000000..e2d1cba
--- /dev/null
+++ b/syzkaller-repros/linux/e4432806b1b9c791b6c3185785fcdbdcd8054d4f.c
@@ -0,0 +1,82 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000340;
+ memcpy(
+ (void*)0x20000340,
+ "\x68\x00\x00\x00\x02\x06\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x12\x00\x03\x00\x62\x69\x74\x6d\x61\x70\x3a\x69\x70\x2c\x6d\x61"
+ "\x63\x00\x00\x00\x09\x00\x02\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x1c\x00"
+ "\x07\x80\x0c\x00\x01\x80\x08\x00\x01\x40\x00\x00\x00\x00\x0c\x00\x02\x80"
+ "\x08\x00\x01\x40\x00\x00\x00\x00\x05\x00\x01\x00\x07\x00\x00\x00\x05\x00"
+ "\x04\x00\x00\x00\x00\x00\x05\x00\x05\x00\x02\x00\x00\x00\xb6\x2a\x12\xfd"
+ "\x74\x8c\xf6\x60\xad\xec\xa6\xc4\xef\x7c\xf1\x6f\x57\xda\x44\x80\xd3\xe4"
+ "\x00\x2e\xd7\xeb\xee\x07\x10\xdc\x9f\x9c\x47\x0c\xfe\x87\xf2\xeb\xa9\xa8"
+ "\x00\xba\x95\xb7\xa4\x02\xca\x8a\x12\x92\x0e\x1c\xf5\x91\x56\xef\x34\x9f"
+ "\xa3\x74\x75\x80\xb1\x2c\x13\x34\x70\x8d\xb7\xbe\x74\xd3\x37\xd2\x35\xaf"
+ "\x31\x36\x68\xd2\x10\xc4\x96\x13\x46\xa5\xaa\xf0\x2e\x46\x87\xeb\x76\xab"
+ "\xd7\x12\xd4\x4f\x2e\xd5\xdd\xc8\x0e\x39\x95\xdd\x0c\x3d\xbb\x56\x4f\x40"
+ "\xa0\x1d\x4a\xbc\x99\x8e\x5a\x35\x70\xf1\xa1\xc0\x09\x0a\x5d\xb8\xf9\x3b"
+ "\x80\xf9\x9c\xc1\xe8\xf9\x36\x93\x5b\x24\x8c\xf6\xe8\x15\xfb\x08\xb5\xc1"
+ "\xfd\x52\xab\xa6\xbe\xe9\xf2\x15\x37\xcf\x05\x05\x76\x1e\x6a\xf1\xee\x83"
+ "\xf5\x18\x27\xac\xc3\xf0\x37\x22\x28\x9f\xee\x28\xce\x31\xa5\x03\x4f\x8d"
+ "\x43\xfe\xfb\x14\xde\x53\x6c\x92\xbe\xa5\x9e\xc3\x5a\xf1\xdc\xe3\x5d\x30"
+ "\xc5\x90\x5c\x00\x18\xb9\x4a\x4f\xc0\x54\x1e\x51\xb2\xf5\x14\xa8\xe7\x0c"
+ "\xb5\x3e\x64\xf6\x4c\x80\xbc\x05\x38\xf5\xe9\xf8\x49\x8a\x09\x55\x82\xf6"
+ "\x3b\x2f",
+ 344);
+ *(uint64_t*)0x200002c8 = 0x68;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c8 = 0;
+ *(uint64_t*)0x200000d0 = 0x20000080;
+ *(uint64_t*)0x20000080 = 0x20000040;
+ *(uint32_t*)0x20000040 = 0x1c;
+ *(uint8_t*)0x20000044 = 8;
+ *(uint8_t*)0x20000045 = 6;
+ *(uint16_t*)0x20000046 = 3;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint8_t*)0x20000050 = 0;
+ *(uint8_t*)0x20000051 = 0;
+ *(uint16_t*)0x20000052 = htobe16(0);
+ *(uint16_t*)0x20000054 = 5;
+ *(uint16_t*)0x20000056 = 1;
+ *(uint8_t*)0x20000058 = 7;
+ *(uint64_t*)0x20000088 = 0x1c;
+ *(uint64_t*)0x200000d8 = 1;
+ *(uint64_t*)0x200000e0 = 0;
+ *(uint64_t*)0x200000e8 = 0;
+ *(uint32_t*)0x200000f0 = 0;
+ syscall(__NR_sendmsg, r[1], 0x200000c0ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e4e5a43811c434e39a8ffd0c4913f213172c77c3.c b/syzkaller-repros/linux/e4e5a43811c434e39a8ffd0c4913f213172c77c3.c
new file mode 100644
index 0000000..f23b21e
--- /dev/null
+++ b/syzkaller-repros/linux/e4e5a43811c434e39a8ffd0c4913f213172c77c3.c
@@ -0,0 +1,286 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x28ul, 1ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20000000 = 0x28;
+ *(uint16_t*)0x20000002 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = -1;
+ *(uint32_t*)0x2000000c = 0;
+ syscall(__NR_connect, r[0], 0x20000000ul, 0x10ul);
+ *(uint16_t*)0x200000c0 = 0x28;
+ *(uint16_t*)0x200000c2 = 0;
+ *(uint32_t*)0x200000c4 = -1;
+ *(uint32_t*)0x200000c8 = 0x4d2;
+ *(uint32_t*)0x200000cc = 0;
+ syscall(__NR_connect, r[0], 0x200000c0ul, 0x10ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e53e20188ca052347cbbade1b1c1c9683991239e.c b/syzkaller-repros/linux/e53e20188ca052347cbbade1b1c1c9683991239e.c
new file mode 100644
index 0000000..e986ca9
--- /dev/null
+++ b/syzkaller-repros/linux/e53e20188ca052347cbbade1b1c1c9683991239e.c
@@ -0,0 +1,422 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_init_net_socket(volatile long domain, volatile long type,
+ volatile long proto)
+{
+ return syscall(__NR_socket, domain, type, proto);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_init_net_socket(0x27, 2, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint16_t*)0x20000140 = 0x27;
+ *(uint32_t*)0x20000144 = 0;
+ *(uint32_t*)0x20000148 = 0;
+ *(uint32_t*)0x2000014c = 0;
+ *(uint8_t*)0x20000150 = 0;
+ *(uint8_t*)0x20000151 = 0;
+ memcpy((void*)0x20000152,
+ "\x6c\xb7\x82\xe4\xad\x88\xb8\x9d\x1f\xd3\x09\x16\x9f\x44\xa7\x21\x07"
+ "\x13\x0e\xe5\x5d\x66\x05\x10\x42\x0a\xaa\x96\x75\x9e\xcb\xc3\x6e\xb9"
+ "\xbb\x12\xb6\x12\x47\x93\x60\x8d\xd0\xe7\x31\x6d\x1d\x4f\x4d\xba\xc3"
+ "\x98\x77\xe4\xac\x71\x4b\x7e\xce\xfa\x8a\x93\x4a",
+ 63);
+ *(uint64_t*)0x20000198 = 1;
+ syscall(__NR_bind, r[0], 0x20000140ul, 0x60ul);
+ syscall(__NR_getpeername, r[0], 0ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e6328edb1d91b5af561439aded6a7d4cb671a90c.c b/syzkaller-repros/linux/e6328edb1d91b5af561439aded6a7d4cb671a90c.c
new file mode 100644
index 0000000..e2b87d4
--- /dev/null
+++ b/syzkaller-repros/linux/e6328edb1d91b5af561439aded6a7d4cb671a90c.c
@@ -0,0 +1,259 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_bpf, 0ul, 0ul, 0ul);
+ syscall(__NR_bpf, 0ul, 0ul, 0ul);
+ NONFAILING(memcpy((void*)0x20000080, "/dev/nbd#\000", 10));
+ res = syz_open_dev(0x20000080, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0xab0aul, 0x10000000de7ul);
+ res = syscall(__NR_socket, 2ul, 1ul, 0);
+ if (res != -1)
+ r[1] = res;
+ syscall(__NR_ioctl, r[0], 0xab00ul, r[1]);
+ res = syz_open_dev(0, 0, 0);
+ if (res != -1)
+ r[2] = res;
+ inject_fault(9);
+ syscall(__NR_ioctl, r[2], 0xab03ul, 0);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e955f8f41c1f05c49439ac95657f0e4df562ad55.c b/syzkaller-repros/linux/e955f8f41c1f05c49439ac95657f0e4df562ad55.c
new file mode 100644
index 0000000..08ba7ec
--- /dev/null
+++ b/syzkaller-repros/linux/e955f8f41c1f05c49439ac95657f0e4df562ad55.c
@@ -0,0 +1,342 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 7; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+#ifndef __NR_io_uring_register
+#define __NR_io_uring_register 427
+#endif
+#ifndef __NR_io_uring_setup
+#define __NR_io_uring_setup 425
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ *(uint32_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000044 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint32_t*)0x2000004c = 0;
+ *(uint32_t*)0x20000050 = 0;
+ *(uint32_t*)0x20000054 = 0;
+ *(uint32_t*)0x20000058 = 0;
+ *(uint32_t*)0x2000005c = 0;
+ *(uint32_t*)0x20000060 = 0;
+ *(uint32_t*)0x20000064 = 0;
+ *(uint32_t*)0x20000068 = 0;
+ *(uint32_t*)0x2000006c = 0;
+ *(uint32_t*)0x20000070 = 0;
+ *(uint32_t*)0x20000074 = 0;
+ *(uint32_t*)0x20000078 = 0;
+ *(uint32_t*)0x2000007c = 0;
+ *(uint32_t*)0x20000080 = 0;
+ *(uint32_t*)0x20000084 = 0;
+ *(uint64_t*)0x20000088 = 0;
+ *(uint32_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000094 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint32_t*)0x200000a0 = 0;
+ *(uint32_t*)0x200000a4 = 0;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint64_t*)0x200000b0 = 0;
+ res = syscall(__NR_io_uring_setup, 0x14a, 0x20000040ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_mmap, 0x20ffd000ul, 0x3000ul, 1ul, 0x10ul, -1, 6ul);
+ break;
+ case 2:
+ *(uint32_t*)0x200003c0 = -1;
+ syscall(__NR_io_uring_register, r[0], 2ul, 0x200003c0ul,
+ 0x40000000000001b2ul);
+ break;
+ case 3:
+ *(uint32_t*)0x200016c0 = 0x1f;
+ *(uint64_t*)0x200016c8 = 0x20001680;
+ *(uint32_t*)0x20001680 = -1;
+ *(uint32_t*)0x20001684 = -1;
+ *(uint32_t*)0x20001688 = -1;
+ syscall(__NR_io_uring_register, r[0], 6ul, 0x200016c0ul, 3ul);
+ break;
+ case 4:
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0x80000ul, 0ul);
+ break;
+ case 5:
+ syscall(__NR_write, -1, 0ul, 0ul);
+ break;
+ case 6:
+ syscall(__NR_fcntl, -1, 0x400ul, 0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 6; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e9b0acb3f0bfed98df05a70d835d3f014bafa045.c b/syzkaller-repros/linux/e9b0acb3f0bfed98df05a70d835d3f014bafa045.c
new file mode 100644
index 0000000..c8e130f
--- /dev/null
+++ b/syzkaller-repros/linux/e9b0acb3f0bfed98df05a70d835d3f014bafa045.c
@@ -0,0 +1,204 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ loop();
+ exit(1);
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0x0};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ res = syscall(__NR_socketpair, 1ul, 5ul, 0ul, 0x200000c0ul);
+ if (res != -1)
+ r[1] = *(uint32_t*)0x200000c4;
+ res = syscall(__NR_dup, r[1]);
+ if (res != -1)
+ r[2] = res;
+ *(uint32_t*)0x20000140 = 0x14;
+ res = syscall(__NR_getsockname, r[2], 0x200000c0ul, 0x20000140ul);
+ if (res != -1)
+ r[3] = *(uint32_t*)0x200000c4;
+ *(uint64_t*)0x20000040 = 0;
+ *(uint32_t*)0x20000048 = 0;
+ *(uint64_t*)0x20000050 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000180;
+ *(uint32_t*)0x20000180 = 0x38;
+ *(uint16_t*)0x20000184 = 0x6d;
+ *(uint16_t*)0x20000186 = 0x705;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint32_t*)0x2000018c = 0;
+ *(uint8_t*)0x20000190 = 0;
+ *(uint8_t*)0x20000191 = 0;
+ *(uint16_t*)0x20000192 = 0;
+ *(uint32_t*)0x20000194 = r[3];
+ *(uint32_t*)0x20000198 = 0;
+ *(uint32_t*)0x2000019c = 0;
+ *(uint16_t*)0x200001a0 = 0x18;
+ STORE_BY_BITMASK(uint16_t, , 0x200001a2, 0x34, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 1, 7, 1);
+ *(uint16_t*)0x200001a4 = 0x14;
+ *(uint16_t*)0x200001a6 = 0x35;
+ memcpy((void*)0x200001a8, "ip6_vti0\000\000\000\000\000\000\000\000", 16);
+ *(uint64_t*)0x200000c8 = 0x38;
+ *(uint64_t*)0x20000058 = 1;
+ *(uint64_t*)0x20000060 = 0;
+ *(uint64_t*)0x20000068 = 0;
+ *(uint32_t*)0x20000070 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000040ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/e9f5b11984c54cecb386b92bb20c76d5d003719f.c b/syzkaller-repros/linux/e9f5b11984c54cecb386b92bb20c76d5d003719f.c
new file mode 100644
index 0000000..b1fa071
--- /dev/null
+++ b/syzkaller-repros/linux/e9f5b11984c54cecb386b92bb20c76d5d003719f.c
@@ -0,0 +1,60 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20001140 = 0;
+ *(uint32_t*)0x20001148 = 0;
+ *(uint64_t*)0x20001150 = 0x20001100;
+ *(uint64_t*)0x20001100 = 0x20000100;
+ memcpy((void*)0x20000100,
+ "\x14\x00\x02\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x1b\x40\x68\xc8\xd5\x72\x7c\xdb\x2f\x27\x1e\x43\xce",
+ 33);
+ *(uint64_t*)0x20001108 = 0x33fe0;
+ *(uint64_t*)0x20001158 = 1;
+ *(uint64_t*)0x20001160 = 0;
+ *(uint64_t*)0x20001168 = 0;
+ *(uint32_t*)0x20001170 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20001140ul, 0ul);
+ *(uint64_t*)0x200004c0 = 0;
+ *(uint32_t*)0x200004c8 = 0;
+ *(uint64_t*)0x200004d0 = 0x20000480;
+ *(uint64_t*)0x20000480 = 0x20000440;
+ *(uint32_t*)0x20000440 = 0x1c;
+ *(uint8_t*)0x20000444 = 1;
+ *(uint8_t*)0x20000445 = 6;
+ *(uint16_t*)0x20000446 = 0x4b35;
+ *(uint32_t*)0x20000448 = 0;
+ *(uint32_t*)0x2000044c = 0;
+ *(uint8_t*)0x20000450 = 7;
+ *(uint8_t*)0x20000451 = 0;
+ *(uint16_t*)0x20000452 = htobe16(6);
+ *(uint16_t*)0x20000454 = 5;
+ *(uint16_t*)0x20000456 = 1;
+ *(uint8_t*)0x20000458 = 7;
+ *(uint64_t*)0x20000488 = 0x1c;
+ *(uint64_t*)0x200004d8 = 1;
+ *(uint64_t*)0x200004e0 = 0;
+ *(uint64_t*)0x200004e8 = 0;
+ *(uint32_t*)0x200004f0 = 0x8010;
+ syscall(__NR_sendmsg, r[0], 0x200004c0ul, 4ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/ea9509cd83e4b2e27f8a9bfbd92c8fd7de381da9.c b/syzkaller-repros/linux/ea9509cd83e4b2e27f8a9bfbd92c8fd7de381da9.c
new file mode 100644
index 0000000..323c068
--- /dev/null
+++ b/syzkaller-repros/linux/ea9509cd83e4b2e27f8a9bfbd92c8fd7de381da9.c
@@ -0,0 +1,769 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, "virt_wifi", name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_virt_wifi(&nlmsg, sock, "virt_wifi0", "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netdevsim_add((int)procid, 4);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ syscall(__NR_recvfrom, -1, 0ul, 0xff76ul, 0ul, 0ul, 0ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0x44ul);
+ syscall(__NR_sendmsg, -1, 0ul, 0x40000ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000240;
+ *(uint32_t*)0x20000240 = 0x70;
+ *(uint8_t*)0x20000244 = 2;
+ *(uint8_t*)0x20000245 = 6;
+ *(uint16_t*)0x20000246 = 1;
+ *(uint32_t*)0x20000248 = 0;
+ *(uint32_t*)0x2000024c = 0;
+ *(uint8_t*)0x20000250 = 0;
+ *(uint8_t*)0x20000251 = 0;
+ *(uint16_t*)0x20000252 = htobe16(0);
+ *(uint16_t*)0x20000254 = 0x12;
+ *(uint16_t*)0x20000256 = 3;
+ memcpy((void*)0x20000258, "bitmap:ip,mac\000", 14);
+ *(uint16_t*)0x20000268 = 9;
+ *(uint16_t*)0x2000026a = 2;
+ memcpy((void*)0x2000026c, "syz0\000", 5);
+ *(uint16_t*)0x20000274 = 0x24;
+ STORE_BY_BITMASK(uint16_t, , 0x20000276, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000277, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000277, 1, 7, 1);
+ *(uint16_t*)0x20000278 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000027a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000027b, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000027b, 1, 7, 1);
+ *(uint16_t*)0x2000027c = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000027e, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000027f, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000027f, 0, 7, 1);
+ *(uint32_t*)0x20000280 = htobe32(0);
+ *(uint16_t*)0x20000284 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x20000286, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000287, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000287, 1, 7, 1);
+ *(uint16_t*)0x20000288 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x2000028a, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000028b, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000028b, 0, 7, 1);
+ *(uint32_t*)0x2000028c = htobe32(0);
+ *(uint16_t*)0x20000290 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000292, 8, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000293, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000293, 0, 7, 1);
+ *(uint32_t*)0x20000294 = htobe32(0x10);
+ *(uint16_t*)0x20000298 = 5;
+ *(uint16_t*)0x2000029a = 1;
+ *(uint8_t*)0x2000029c = 7;
+ *(uint16_t*)0x200002a0 = 5;
+ *(uint16_t*)0x200002a2 = 4;
+ *(uint8_t*)0x200002a4 = 0;
+ *(uint16_t*)0x200002a8 = 5;
+ *(uint16_t*)0x200002aa = 5;
+ *(uint8_t*)0x200002ac = 2;
+ *(uint64_t*)0x200002c8 = 0x70;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/ec4dcfe1da2f9c2560285cf6033991a2ad84950d.c b/syzkaller-repros/linux/ec4dcfe1da2f9c2560285cf6033991a2ad84950d.c
new file mode 100644
index 0000000..f97ec82
--- /dev/null
+++ b/syzkaller-repros/linux/ec4dcfe1da2f9c2560285cf6033991a2ad84950d.c
@@ -0,0 +1,226 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ *(uint64_t*)0x20001000 = 0;
+ *(uint32_t*)0x20001008 = 0;
+ *(uint64_t*)0x20001010 = 0;
+ *(uint64_t*)0x20001018 = 1;
+ *(uint64_t*)0x20001020 = 0;
+ *(uint64_t*)0x20001028 = 0;
+ *(uint32_t*)0x20001030 = 0;
+ syscall(__NR_sendmsg, -1, 0x20001000, 0);
+ *(uint32_t*)0x20001000 = 0x10000;
+ *(uint32_t*)0x20001004 = 4;
+ *(uint32_t*)0x20001008 = 0x100;
+ *(uint32_t*)0x2000100c = 0x400;
+ syscall(__NR_setsockopt, -1, 0x84, 0, 0x20001000, 0xffffffffffffff6e);
+ res = syscall(__NR_socket, 0x11, 0x4000000000080003, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x206e8000 = 2;
+ syscall(__NR_setsockopt, r[0], 0x107, 0xa, 0x206e8000, 4);
+ syscall(__NR_setsockopt, r[0], 0x107, 0xd, 0x20001000, 0x1fd);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/edbf736874b3fd00db172173256731c6b1123883.c b/syzkaller-repros/linux/edbf736874b3fd00db172173256731c6b1123883.c
new file mode 100644
index 0000000..7a90a69
--- /dev/null
+++ b/syzkaller-repros/linux/edbf736874b3fd00db172173256731c6b1123883.c
@@ -0,0 +1,201 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+__attribute__((noreturn)) static void doexit(int status)
+{
+ volatile unsigned i;
+ syscall(__NR_exit_group, status);
+ for (i = 0;; i++) {
+ }
+}
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+const int kFailStatus = 67;
+const int kRetryStatus = 69;
+
+static void fail(const char* msg, ...)
+{
+ int e = errno;
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, " (errno %d)\n", e);
+ doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
+}
+
+static uint64_t current_time_ms()
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ fail("clock_gettime failed");
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static uintptr_t syz_open_procfs(uintptr_t a0, uintptr_t a1)
+{
+
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ if (a0 == 0) {
+ snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1);
+ } else if (a0 == (uintptr_t)-1) {
+ snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1);
+ } else {
+ snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0, (char*)a1);
+ }
+ int fd = open(buf, O_RDWR);
+ if (fd == -1)
+ fd = open(buf, O_RDONLY);
+ return fd;
+}
+
+static void execute_one();
+extern unsigned long long procid;
+
+static void loop()
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ fail("clone failed");
+ if (pid == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ execute_one();
+ doexit(0);
+ }
+
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ int res = waitpid(-1, &status, __WALL | WNOHANG);
+ if (res == pid) {
+ break;
+ }
+ usleep(1000);
+ if (current_time_ms() - start < 3 * 1000)
+ continue;
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ break;
+ }
+ }
+}
+
+struct thread_t {
+ int created, running, call;
+ pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ }
+ return 0;
+}
+
+static void execute(int num_calls)
+{
+ int call, thread;
+ running = 0;
+ for (call = 0; call < num_calls; call++) {
+ for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ pthread_create(&th->th, &attr, thr, th);
+ }
+ if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &th->running, FUTEX_WAKE);
+ if (collide && call % 2)
+ break;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000;
+ syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+ if (running)
+ usleep((call == num_calls - 1) ? 10000 : 1000);
+ break;
+ }
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+void execute_call(int call)
+{
+ long res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x204c6f8b, "mounts", 7);
+ res = syz_open_procfs(0, 0x204c6f8b);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint64_t*)0x20000580 = 0x20003400;
+ *(uint64_t*)0x20000588 = 0x1000;
+ syscall(__NR_preadv, r[0], 0x20000580, 1, 0);
+ break;
+ }
+}
+
+void execute_one()
+{
+ execute(2);
+ collide = 1;
+ execute(2);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ for (;;) {
+ loop();
+ }
+}
diff --git a/syzkaller-repros/linux/efb8c5fe01ecb5116825ce2409485c164c048f88.c b/syzkaller-repros/linux/efb8c5fe01ecb5116825ce2409485c164c048f88.c
new file mode 100644
index 0000000..12d3b93
--- /dev/null
+++ b/syzkaller-repros/linux/efb8c5fe01ecb5116825ce2409485c164c048f88.c
@@ -0,0 +1,245 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000300 = 0;
+ *(uint32_t*)0x20000308 = 0;
+ *(uint64_t*)0x20000310 = 0x200002c0;
+ *(uint64_t*)0x200002c0 = 0x20000440;
+ *(uint32_t*)0x20000440 = 0x50;
+ *(uint8_t*)0x20000444 = 2;
+ *(uint8_t*)0x20000445 = 6;
+ *(uint16_t*)0x20000446 = 1;
+ *(uint32_t*)0x20000448 = 0;
+ *(uint32_t*)0x2000044c = 0;
+ *(uint8_t*)0x20000450 = 0;
+ *(uint8_t*)0x20000451 = 0;
+ *(uint16_t*)0x20000452 = htobe16(0);
+ *(uint16_t*)0x20000454 = 9;
+ *(uint16_t*)0x20000456 = 2;
+ memcpy((void*)0x20000458, "syz2\000", 5);
+ *(uint16_t*)0x20000460 = 0xc;
+ *(uint16_t*)0x20000462 = 3;
+ memcpy((void*)0x20000464, "hash:ip\000", 8);
+ *(uint16_t*)0x2000046c = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x2000046e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000046f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000046f, 1, 7, 1);
+ *(uint16_t*)0x20000470 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x20000472, 6, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x20000473, 0, 7, 1);
+ *(uint32_t*)0x20000474 = htobe32(0);
+ *(uint16_t*)0x20000478 = 5;
+ *(uint16_t*)0x2000047a = 1;
+ *(uint8_t*)0x2000047c = 7;
+ *(uint16_t*)0x20000480 = 5;
+ *(uint16_t*)0x20000482 = 4;
+ *(uint8_t*)0x20000484 = 0;
+ *(uint16_t*)0x20000488 = 5;
+ *(uint16_t*)0x2000048a = 5;
+ *(uint8_t*)0x2000048c = 2;
+ *(uint64_t*)0x200002c8 = 0x50;
+ *(uint64_t*)0x20000318 = 1;
+ *(uint64_t*)0x20000320 = 0x200000000000000;
+ *(uint64_t*)0x20000328 = 0;
+ *(uint32_t*)0x20000330 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+ if (res != -1)
+ r[1] = res;
+ *(uint64_t*)0x20000d00 = 0;
+ *(uint32_t*)0x20000d08 = 0;
+ *(uint64_t*)0x20000d10 = 0x20000cc0;
+ *(uint64_t*)0x20000cc0 = 0x20000180;
+ *(uint32_t*)0x20000180 = 0x44;
+ *(uint8_t*)0x20000184 = 9;
+ *(uint8_t*)0x20000185 = 6;
+ *(uint16_t*)0x20000186 = 0x801;
+ *(uint32_t*)0x20000188 = 0;
+ *(uint32_t*)0x2000018c = 0;
+ *(uint8_t*)0x20000190 = 0;
+ *(uint8_t*)0x20000191 = 0;
+ *(uint16_t*)0x20000192 = htobe16(0);
+ *(uint16_t*)0x20000194 = 5;
+ *(uint16_t*)0x20000196 = 1;
+ *(uint8_t*)0x20000198 = 7;
+ *(uint16_t*)0x2000019c = 0x1c;
+ STORE_BY_BITMASK(uint16_t, , 0x2000019e, 7, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019f, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x2000019f, 1, 7, 1);
+ *(uint16_t*)0x200001a0 = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001a2, 2, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a3, 1, 7, 1);
+ *(uint16_t*)0x200001a4 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001a6, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a7, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001a7, 0, 7, 1);
+ *(uint32_t*)0x200001a8 = htobe32(0);
+ *(uint16_t*)0x200001ac = 0xc;
+ STORE_BY_BITMASK(uint16_t, , 0x200001ae, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001af, 0, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001af, 1, 7, 1);
+ *(uint16_t*)0x200001b0 = 8;
+ STORE_BY_BITMASK(uint16_t, , 0x200001b2, 1, 0, 14);
+ STORE_BY_BITMASK(uint16_t, , 0x200001b3, 1, 6, 1);
+ STORE_BY_BITMASK(uint16_t, , 0x200001b3, 0, 7, 1);
+ *(uint32_t*)0x200001b4 = htobe32(-1);
+ *(uint16_t*)0x200001b8 = 9;
+ *(uint16_t*)0x200001ba = 2;
+ memcpy((void*)0x200001bc, "syz2\000", 5);
+ *(uint64_t*)0x20000cc8 = 0x44;
+ *(uint64_t*)0x20000d18 = 1;
+ *(uint64_t*)0x20000d20 = 0;
+ *(uint64_t*)0x20000d28 = 0;
+ *(uint32_t*)0x20000d30 = 0;
+ syscall(__NR_sendmsg, r[1], 0x20000d00ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/efdaf08406adeccaf182b7a15193f0f71e44bbca.c b/syzkaller-repros/linux/efdaf08406adeccaf182b7a15193f0f71e44bbca.c
new file mode 100644
index 0000000..2a811a6
--- /dev/null
+++ b/syzkaller-repros/linux/efdaf08406adeccaf182b7a15193f0f71e44bbca.c
@@ -0,0 +1,20 @@
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <endian.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+void loop()
+{
+ syscall(__NR_mremap, 0x2000d000, 0xfffffffffffffe74, 0x1000, 3, 0x20007000);
+}
+
+int main()
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f083f6f60c98f51945eb4ec80c1d06ea6bd0e9de.c b/syzkaller-repros/linux/f083f6f60c98f51945eb4ec80c1d06ea6bd0e9de.c
new file mode 100644
index 0000000..c34f11f
--- /dev/null
+++ b/syzkaller-repros/linux/f083f6f60c98f51945eb4ec80c1d06ea6bd0e9de.c
@@ -0,0 +1,359 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 137
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ netlink_send(&nlmsg, sock);
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[5] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0x0};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_pipe2, 0x20000280ul, 0x80800ul);
+ if (res != -1)
+ r[0] = *(uint32_t*)0x20000284;
+ memcpy((void*)0x20000000, "/dev/video#\000", 12);
+ res = syz_open_dev(0x20000000, 3, 0x40000);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000200, "./file0\000", 8);
+ res = syscall(__NR_open, 0x20000200ul, 0x40ul, 0ul);
+ if (res != -1)
+ r[2] = res;
+ memcpy((void*)0x200012c0, "/dev/video#\000", 12);
+ res = syz_open_dev(0x200012c0, 6, 0xe8122);
+ if (res != -1)
+ r[3] = res;
+ res = syscall(__NR_getuid);
+ if (res != -1)
+ r[4] = res;
+ memcpy((void*)0x20000040, "./file0\000", 8);
+ memcpy((void*)0x20000080, "9p\000", 3);
+ memcpy((void*)0x200000c0, "trans=fd,", 9);
+ memcpy((void*)0x200000c9, "rfdno", 5);
+ *(uint8_t*)0x200000ce = 0x3d;
+ sprintf((char*)0x200000cf, "0x%016llx", (long long)r[2]);
+ *(uint8_t*)0x200000e1 = 0x2c;
+ memcpy((void*)0x200000e2, "wfdno", 5);
+ *(uint8_t*)0x200000e7 = 0x3d;
+ sprintf((char*)0x200000e8, "0x%016llx", (long long)r[3]);
+ *(uint8_t*)0x200000fa = 0x2c;
+ memcpy((void*)0x200000fb, "mmap", 4);
+ *(uint8_t*)0x200000ff = 0x2c;
+ memcpy((void*)0x20000100, "appraise_type=imasig", 20);
+ *(uint8_t*)0x20000114 = 0x2c;
+ memcpy((void*)0x20000115, "uid<", 4);
+ sprintf((char*)0x20000119, "%020llu", (long long)0);
+ *(uint8_t*)0x2000012d = 0x2c;
+ memcpy((void*)0x2000012e, "fsname", 6);
+ *(uint8_t*)0x20000134 = 0x3d;
+ memcpy((void*)0x20000135, "/dev/video#\000", 12);
+ *(uint8_t*)0x20000141 = 0x2c;
+ memcpy((void*)0x20000142, "uid", 3);
+ *(uint8_t*)0x20000145 = 0x3d;
+ sprintf((char*)0x20000146, "%020llu", (long long)0);
+ *(uint8_t*)0x2000015a = 0x2c;
+ memcpy((void*)0x2000015b, "pcr", 3);
+ *(uint8_t*)0x2000015e = 0x3d;
+ sprintf((char*)0x2000015f, "%020llu", (long long)4);
+ *(uint8_t*)0x20000173 = 0x2c;
+ memcpy((void*)0x20000174, "fowner", 6);
+ *(uint8_t*)0x2000017a = 0x3d;
+ sprintf((char*)0x2000017b, "%020llu", (long long)0);
+ *(uint8_t*)0x2000018f = 0x2c;
+ memcpy((void*)0x20000190, "uid", 3);
+ *(uint8_t*)0x20000193 = 0x3d;
+ sprintf((char*)0x20000194, "%020llu", (long long)0);
+ *(uint8_t*)0x200001a8 = 0x2c;
+ memcpy((void*)0x200001a9, "mask", 4);
+ *(uint8_t*)0x200001ad = 0x3d;
+ memcpy((void*)0x200001ae, "MAY_READ", 8);
+ *(uint8_t*)0x200001b6 = 0x2c;
+ memcpy((void*)0x200001b7, "fowner<", 7);
+ sprintf((char*)0x200001be, "%020llu", (long long)r[4]);
+ *(uint8_t*)0x200001d2 = 0x2c;
+ memcpy((void*)0x200001d3, "measure", 7);
+ *(uint8_t*)0x200001da = 0x2c;
+ *(uint8_t*)0x200001db = 0;
+ syscall(__NR_mount, 0ul, 0x20000040ul, 0x20000080ul, 0x400ul, 0x200000c0ul);
+ syscall(__NR_splice, r[1], 0ul, r[0], 0ul, 0xfffffffffffffffbul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f1207160d29ff8806029b7233fd54322d44f6572.c b/syzkaller-repros/linux/f1207160d29ff8806029b7233fd54322d44f6572.c
new file mode 100644
index 0000000..abc4e0e
--- /dev/null
+++ b/syzkaller-repros/linux/f1207160d29ff8806029b7233fd54322d44f6572.c
@@ -0,0 +1,296 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ memcpy((void*)0x20000000, "/dev/ndctl0\000", 12);
+ res =
+ syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0x180102ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x20000380 = 3;
+ STORE_BY_BITMASK(uint8_t, , 0x20000381, 0, 0, 7);
+ STORE_BY_BITMASK(uint8_t, , 0x20000381, 0, 7, 1);
+ *(uint32_t*)0x20000384 = 0;
+ *(uint32_t*)0x20000388 = 0xf2;
+ *(uint64_t*)0x20000390 = 0;
+ *(uint32_t*)0x20000398 = 0;
+ *(uint32_t*)0x2000039c = 0;
+ *(uint32_t*)0x200003a0 = 0;
+ *(uint32_t*)0x200003a4 = 0;
+ *(uint32_t*)0x200003a8 = 0;
+ *(uint32_t*)0x200003ac = 0;
+ *(uint64_t*)0x200003b0 = 0;
+ syscall(__NR_ioctl, r[0], 0x8038550aul, 0x20000380ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f46698eabd542bcae3e24d1be3d179a23cd7c6eb.c b/syzkaller-repros/linux/f46698eabd542bcae3e24d1be3d179a23cd7c6eb.c
new file mode 100644
index 0000000..d4ca8d7
--- /dev/null
+++ b/syzkaller-repros/linux/f46698eabd542bcae3e24d1be3d179a23cd7c6eb.c
@@ -0,0 +1,307 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ memcpy((void*)0x200000c0, "\xb6", 1);
+ syscall(__NR_ioctl, r[0], 0x4b61ul, 0x200000c0ul);
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[1] = res;
+ *(uint16_t*)0x200002c0 = 0;
+ *(uint16_t*)0x200002c2 = 0;
+ *(uint16_t*)0x200002c4 = 0;
+ *(uint16_t*)0x200002c6 = 9;
+ *(uint16_t*)0x200002c8 = 2;
+ *(uint16_t*)0x200002ca = 1;
+ syscall(__NR_ioctl, r[1], 0x560aul, 0x200002c0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f56ab692e7055a5edf3da099ae9c11d21242c42d.c b/syzkaller-repros/linux/f56ab692e7055a5edf3da099ae9c11d21242c42d.c
new file mode 100644
index 0000000..cea8a87
--- /dev/null
+++ b/syzkaller-repros/linux/f56ab692e7055a5edf3da099ae9c11d21242c42d.c
@@ -0,0 +1,1050 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint64_t*)0x20000010 = 0x200000c0;
+ *(uint64_t*)0x200000c0 = 0x20000100;
+ memcpy((void*)0x20000100,
+ "\x38\x00\x00\x00\x03\x14\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09"
+ "\x00\x02\x40\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x41\x00\x72\x78"
+ "\x65\x00\x14\x00\x33\x00\x76\x6c\x61\x6e\x30\x00\x00\x00\x00\x00\x08"
+ "\x00\x00\x00\x00\x00",
+ 56);
+ *(uint64_t*)0x200000c8 = 0x38;
+ *(uint64_t*)0x20000018 = 1;
+ *(uint64_t*)0x20000020 = 0;
+ *(uint64_t*)0x20000028 = 0;
+ *(uint32_t*)0x20000030 = 0;
+ syscall(__NR_sendmsg, r[0], 0x20000000ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f5705df7b6e0573321a2e322ef7e0d3af68cea1a.c b/syzkaller-repros/linux/f5705df7b6e0573321a2e322ef7e0d3af68cea1a.c
new file mode 100644
index 0000000..bb900ff
--- /dev/null
+++ b/syzkaller-repros/linux/f5705df7b6e0573321a2e322ef7e0d3af68cea1a.c
@@ -0,0 +1,20 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ syscall(__NR_unshare, 0x8000000ul);
+ syscall(__NR_shmget, 0ul, 0xfffffffffefffffful, 0x4800ul, 0x20ffc000ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f57556adc921a352d4449d9bc8569d9f08fe0da3.c b/syzkaller-repros/linux/f57556adc921a352d4449d9bc8569d9f08fe0da3.c
new file mode 100644
index 0000000..f61ded6
--- /dev/null
+++ b/syzkaller-repros/linux/f57556adc921a352d4449d9bc8569d9f08fe0da3.c
@@ -0,0 +1,321 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ for (call = 0; call < 10; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ memcpy((void*)0x20000240, "./file1\000", 8);
+ syscall(__NR_mkdir, 0x20000240ul, 0ul);
+ break;
+ case 1:
+ memcpy((void*)0x20000180, "./bus\000", 6);
+ syscall(__NR_mkdir, 0x20000180ul, 0ul);
+ break;
+ case 2:
+ memcpy((void*)0x200000c0, "./bus/file0\000", 12);
+ res = syscall(__NR_creat, 0x200000c0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 3:
+ *(uint32_t*)0x20000040 = 0;
+ *(uint8_t*)0x20000044 = 0;
+ *(uint8_t*)0x20000045 = 0;
+ *(uint8_t*)0x20000046 = 0;
+ *(uint8_t*)0x20000047 = 0;
+ syscall(__NR_write, r[0], 0x20000040ul, 0x5577b540ul);
+ break;
+ case 4:
+ memcpy((void*)0x20000280, "./file0\000", 8);
+ syscall(__NR_mkdir, 0x20000280ul, 0ul);
+ break;
+ case 5:
+ memcpy((void*)0x20000000, "./bus\000", 6);
+ memcpy((void*)0x20000080, "overlay\000", 8);
+ memcpy((void*)0x20000100, "lowerdir=./bus,workdir=./file1,upperdir=./file0",
+ 47);
+ syscall(__NR_mount, 0x400000ul, 0x20000000ul, 0x20000080ul, 0ul,
+ 0x20000100ul);
+ break;
+ case 6:
+ memcpy((void*)0x200002c0, "./bus\000", 6);
+ syscall(__NR_chdir, 0x200002c0ul);
+ break;
+ case 7:
+ memcpy((void*)0x20000200, "./file0\000", 8);
+ res = syscall(__NR_open, 0x20000200ul, 0ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 8:
+ memcpy((void*)0x20000000, "./file0\000", 8);
+ syscall(__NR_lchown, 0x20000000ul, 0, 0);
+ break;
+ case 9:
+ syscall(__NR_lseek, r[1], 0ul, 4ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f711915bab4424dc49beba5ac02e23e6c906449c.c b/syzkaller-repros/linux/f711915bab4424dc49beba5ac02e23e6c906449c.c
new file mode 100644
index 0000000..636a721
--- /dev/null
+++ b/syzkaller-repros/linux/f711915bab4424dc49beba5ac02e23e6c906449c.c
@@ -0,0 +1,245 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = \
+ htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+void execute_one(void)
+{
+ *(uint32_t*)0x20000080 = 0xe;
+ *(uint32_t*)0x20000084 = 3;
+ *(uint64_t*)0x20000088 = 0x20001fd8;
+ *(uint8_t*)0x20001fd8 = 0x85;
+ STORE_BY_BITMASK(uint8_t, , 0x20001fd9, 0, 0, 4);
+ STORE_BY_BITMASK(uint8_t, , 0x20001fd9, 0, 4, 4);
+ *(uint16_t*)0x20001fda = 0;
+ *(uint32_t*)0x20001fdc = 8;
+ *(uint8_t*)0x20001fe0 = 0x3d;
+ *(uint8_t*)0x20001fe1 = 0;
+ *(uint16_t*)0x20001fe2 = 0;
+ *(uint32_t*)0x20001fe4 = 0;
+ *(uint8_t*)0x20001fe8 = 0x95;
+ *(uint8_t*)0x20001fe9 = 0;
+ *(uint16_t*)0x20001fea = 0;
+ *(uint32_t*)0x20001fec = 0;
+ *(uint64_t*)0x20000090 = 0x20000000;
+ memcpy((void*)0x20000000, "GPL\000", 4);
+ *(uint32_t*)0x20000098 = 5;
+ *(uint32_t*)0x2000009c = 0x252;
+ *(uint64_t*)0x200000a0 = 0x2000cf3d;
+ *(uint32_t*)0x200000a8 = 0;
+ *(uint32_t*)0x200000ac = 0;
+ *(uint8_t*)0x200000b0 = 0;
+ *(uint8_t*)0x200000b1 = 0;
+ *(uint8_t*)0x200000b2 = 0;
+ *(uint8_t*)0x200000b3 = 0;
+ *(uint8_t*)0x200000b4 = 0;
+ *(uint8_t*)0x200000b5 = 0;
+ *(uint8_t*)0x200000b6 = 0;
+ *(uint8_t*)0x200000b7 = 0;
+ *(uint8_t*)0x200000b8 = 0;
+ *(uint8_t*)0x200000b9 = 0;
+ *(uint8_t*)0x200000ba = 0;
+ *(uint8_t*)0x200000bb = 0;
+ *(uint8_t*)0x200000bc = 0;
+ *(uint8_t*)0x200000bd = 0;
+ *(uint8_t*)0x200000be = 0;
+ *(uint8_t*)0x200000bf = 0;
+ *(uint32_t*)0x200000c0 = 0;
+ *(uint32_t*)0x200000c4 = 0;
+ *(uint32_t*)0x200000c8 = -1;
+ *(uint32_t*)0x200000cc = 8;
+ *(uint64_t*)0x200000d0 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x200000d8 = 0x262;
+ *(uint32_t*)0x200000dc = 0x10;
+ *(uint64_t*)0x200000e0 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0;
+ *(uint32_t*)0x20000004 = 0;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0;
+ *(uint32_t*)0x200000e8 = 0;
+ *(uint32_t*)0x200000ec = 0;
+ *(uint32_t*)0x200000f0 = -1;
+ inject_fault(21);
+ syscall(__NR_bpf, 5ul, 0x20000080ul, 0x48ul);
+}
+int main(void)
+{
+ inject_fault(21);
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f73b3116ad434cc9b97b908060b5e73752df3be7.c b/syzkaller-repros/linux/f73b3116ad434cc9b97b908060b5e73752df3be7.c
new file mode 100644
index 0000000..23c1de3
--- /dev/null
+++ b/syzkaller-repros/linux/f73b3116ad434cc9b97b908060b5e73752df3be7.c
@@ -0,0 +1,386 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_genetlink_get_family_id(volatile long name)
+{
+ char buf[512] = {0};
+ struct nlmsghdr* hdr = (struct nlmsghdr*)buf;
+ struct genlmsghdr* genlhdr = (struct genlmsghdr*)NLMSG_DATA(hdr);
+ struct nlattr* attr = (struct nlattr*)(genlhdr + 1);
+ hdr->nlmsg_len =
+ sizeof(*hdr) + sizeof(*genlhdr) + sizeof(*attr) + GENL_NAMSIZ;
+ hdr->nlmsg_type = GENL_ID_CTRL;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ genlhdr->cmd = CTRL_CMD_GETFAMILY;
+ attr->nla_type = CTRL_ATTR_FAMILY_NAME;
+ attr->nla_len = sizeof(*attr) + GENL_NAMSIZ;
+ NONFAILING(strncpy((char*)(attr + 1), (char*)name, GENL_NAMSIZ));
+ struct iovec iov = {hdr, hdr->nlmsg_len};
+ struct sockaddr_nl addr = {0};
+ addr.nl_family = AF_NETLINK;
+ int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (fd == -1) {
+ return -1;
+ }
+ struct msghdr msg = {&addr, sizeof(addr), &iov, 1, NULL, 0, 0};
+ if (sendmsg(fd, &msg, 0) == -1) {
+ close(fd);
+ return -1;
+ }
+ ssize_t n = recv(fd, buf, sizeof(buf), 0);
+ close(fd);
+ if (n <= 0) {
+ return -1;
+ }
+ if (hdr->nlmsg_type != GENL_ID_CTRL) {
+ return -1;
+ }
+ for (; (char*)attr < buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID)
+ return *(uint16_t*)(attr + 1);
+ }
+ return -1;
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x10ul);
+ if (res != -1)
+ r[0] = res;
+ NONFAILING(memcpy((void*)0x200000c0, "nl80211\000", 8));
+ res = syz_genetlink_get_family_id(0x200000c0);
+ if (res != -1)
+ r[1] = res;
+ NONFAILING(*(uint64_t*)0x200000c0 = 0);
+ NONFAILING(*(uint32_t*)0x200000c8 = 0);
+ NONFAILING(*(uint64_t*)0x200000d0 = 0x20000080);
+ NONFAILING(*(uint64_t*)0x20000080 = 0x20000100);
+ NONFAILING(memcpy((void*)0x20000100, "\x1c\x00\x00\x00", 4));
+ NONFAILING(*(uint16_t*)0x20000104 = r[1]);
+ NONFAILING(memcpy(
+ (void*)0x20000106,
+ "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x06\x00\x21\x00"
+ "\x00\x00\x00\x00\x57\x0f\x8d\xb8\x46\xec\xda\x2d\x91\xc3\x84\xb2\xac\x89"
+ "\x11\x6b\xdd\xa9\xf6\xa3\x27\xae\x6f\x85\x77\x1a\x63\xe1\x12\x5a\xf7\xcf"
+ "\xc7\x44\x84\xf4\x0d\xb3\x20\xc0\xcc\x9d\x90\x25\xb4\x9d\xfd\x8d\x9f\x31"
+ "\x3a\x95\x33\x6e\x13\xa0\x63\xe1\xd1\x40\x33\x3f\x5e\x13\x18\x5d\x2d\x30"
+ "\xe3\xad\x84\x8c\xeb\xd3\x28\xf6\x3d\x7b\xee\x7f\xda\x05\xc1\x3b\xb0\x32"
+ "\x60\x4c\xf4\x42\xab\x9b\x3a\xaf\x41\x5f\x04\x68\x96\x34\xa2\x06\x09\x78"
+ "\xb7\xea\xde\x83\xaa\x28\xe6\xd4\xf2\xc3\x20\xa2\x5c\x29\x3c\xc5\x0e\xcf"
+ "\xfd\x4b\x94\x61\xcd\x20\xd0\x8b\x0e\x43",
+ 154));
+ NONFAILING(*(uint64_t*)0x20000088 = 0x1c);
+ NONFAILING(*(uint64_t*)0x200000d8 = 1);
+ NONFAILING(*(uint64_t*)0x200000e0 = 0);
+ NONFAILING(*(uint64_t*)0x200000e8 = 0);
+ NONFAILING(*(uint32_t*)0x200000f0 = 0);
+ syscall(__NR_sendmsg, r[0], 0x200000c0ul, 0ul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f77562bab0c7b54949eeb4f670a42406ebe6987c.c b/syzkaller-repros/linux/f77562bab0c7b54949eeb4f670a42406ebe6987c.c
new file mode 100644
index 0000000..96951ca
--- /dev/null
+++ b/syzkaller-repros/linux/f77562bab0c7b54949eeb4f670a42406ebe6987c.c
@@ -0,0 +1,530 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000100, "/dev/vhci\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000100ul, 2ul, 0);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x20000000 = -1;
+ *(uint8_t*)0x20000001 = 0;
+ syscall(__NR_write, r[0], 0x20000000ul, 2ul);
+ *(uint8_t*)0x20000040 = 4;
+ memcpy(
+ (void*)0x20000041,
+ "\x2f\x01\xb4\xa5\x7f\xf6\x30\xb8\xb7\xb6\x5e\x0a\x42\x4a\x7c\x43\x6e\x8a"
+ "\xd8\x89\x17\x71\x17\x1e\xb0\x16\x43\xc5\xa3\xf5\x3e\xf4\xf0\x41\x32\x58"
+ "\xe7\xee\x40\xd6\xdb\x6d\x6f\x75\x2a\x89\xa0\x55\x89\x32\x6a\x29\xc6\xb4"
+ "\x43\x5a\xd2\xb4\xc4\xa3\x33\x84\xc3\x16\x27\x4d\x9d\x69\x18\xcc\x1c\xd7"
+ "\x3f\xad\x4b\x7b\xf7\xcc\x9f\x8e\x87\x11\x4d\xc4\x92\xb8\xd2\x0e\xc4\xd0"
+ "\x3f\xca\xad\x9f\x8e\xcb\x03\x4a\x06\xba\xe7\x63\xf2\xac\xfc\x7a\xa8\x45"
+ "\x97\x74\x74\xa7\xda\xdc\x1f\x92\x08\x01\xd8\xcc\x67\x15\xfb\x9f\x45\x66"
+ "\x9b\xcd\x3c\x23\xaa\x49\x98\x25\x1f\xc3\x1f\xca\x39\x06\xc2\x57\xc9\xc6"
+ "\x98\xe6\xb2\x83\x90\x28\x3d\x37\x56\xa5",
+ 154);
+ syscall(__NR_write, r[0], 0x20000040ul, 0x9bul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f7b9b47b8a12b6ff7a434d6f908d38699e08ada0.c b/syzkaller-repros/linux/f7b9b47b8a12b6ff7a434d6f908d38699e08ada0.c
new file mode 100644
index 0000000..7bafd10
--- /dev/null
+++ b/syzkaller-repros/linux/f7b9b47b8a12b6ff7a434d6f908d38699e08ada0.c
@@ -0,0 +1,612 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syz_open_dev(0, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ syscall(__NR_ioctl, r[0], 0x702ul, 0ul);
+ break;
+ case 2:
+ NONFAILING(memcpy((void*)0x20000080, "/dev/i2c-#\000", 11));
+ res = syz_open_dev(0x20000080, 0, 0);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 3:
+ NONFAILING(*(uint8_t*)0x200000c0 = 1);
+ NONFAILING(*(uint8_t*)0x200000c1 = 3);
+ NONFAILING(*(uint32_t*)0x200000c4 = 6);
+ NONFAILING(*(uint64_t*)0x200000c8 = 0x20000040);
+ NONFAILING(*(uint8_t*)0x20000040 = 0xc);
+ NONFAILING(memcpy(
+ (void*)0x20000041,
+ "\x42\x6d\x54\x73\x4a\xed\x75\xd0\xa6\x36\x81\xc4\xa0\x34\xea\xba\xbb"
+ "\xb1\xdd\xd0\xaf\xe6\xca\xe4\xa6\x46\xa2\xad\x9c\xc8\x82\x5e\x76",
+ 33));
+ syscall(__NR_ioctl, r[1], 0x720ul, 0x200000c0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f7e0bba8c3e53fe21a4a60bc232356b7d704f634.c b/syzkaller-repros/linux/f7e0bba8c3e53fe21a4a60bc232356b7d704f634.c
new file mode 100644
index 0000000..8b1fd1f
--- /dev/null
+++ b/syzkaller-repros/linux/f7e0bba8c3e53fe21a4a60bc232356b7d704f634.c
@@ -0,0 +1,446 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syz_open_dev(0xc, 4, 1);
+ if (res != -1)
+ r[0] = res;
+ *(uint8_t*)0x20000040 = 2;
+ *(uint16_t*)0x20000041 = 0;
+ *(uint16_t*)0x20000043 = 9;
+ *(uint16_t*)0x20000045 = 0;
+ *(uint16_t*)0x20000047 = 0;
+ *(uint16_t*)0x20000049 = 0;
+ syscall(__NR_ioctl, r[0], 0x541cul, 0x20000040ul);
+ memcpy((void*)0x20000000, "/dev/vcsa\000\000", 11);
+ res = syz_open_dev(0x20000000, 0, 0x2001);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000180,
+ "\x23\x21\x20\x2e\x2f\x66\x69\x6c\x65\x30\x0a\xfb\x37\x1b\xfa\x31\xfd"
+ "\x77\x16\x93\xa4\x38\xbb\x89\x0f\x5a\xbb\x69\xa0\xa7\x74\xc4\x24\xd4"
+ "\xbf\x55\x3c\x74\x5e\x03\x96\x6b\x65\xce\x0c\xfb\xc3\x97\xcf\x23\x19"
+ "\x61\x0e\x6f\xdb\x42\xe0\x35\xc5\x7f\x4d\xb7\xf5\x79\x9e\x51\x5f\x62"
+ "\xf9\xa7\x4b\xf9\x1a\x90\xfe\x68\x2d\x6b\x9b\x9b\x73\x97\xd3\xd8\xa2"
+ "\xa4\xed\x3f\xcc\xc4\x9b\x36\x00\x0f\x6e",
+ 95);
+ syscall(__NR_write, r[1], 0x20000180ul, 0x5ful);
+ res = syz_open_dev(0xc, 4, 3);
+ if (res != -1)
+ r[2] = res;
+ *(uint8_t*)0x20000140 = 3;
+ syscall(__NR_ioctl, r[2], 0x541cul, 0x20000140ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f7f424f89ff5d010aefc0ae8cfeeb1186bcfd0da.c b/syzkaller-repros/linux/f7f424f89ff5d010aefc0ae8cfeeb1186bcfd0da.c
new file mode 100644
index 0000000..ea24f13
--- /dev/null
+++ b/syzkaller-repros/linux/f7f424f89ff5d010aefc0ae8cfeeb1186bcfd0da.c
@@ -0,0 +1,1198 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
+ (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ char buf[1024];
+ char* hash;
+ NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10);
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 35; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[14] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ NONFAILING(memcpy((void*)0x20000000, "/dev/vcsu#\000", 11));
+ res = syz_open_dev(0x20000000, 4, 0x4000);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ NONFAILING(*(uint32_t*)0x20000040 = 1);
+ NONFAILING(*(uint32_t*)0x20000044 = 0);
+ NONFAILING(
+ memcpy((void*)0x20000048, "\x61\xfc\xfb\x15\x14\xd8\x95\x90", 8));
+ NONFAILING(*(uint32_t*)0x20000068 = 0xea);
+ NONFAILING(*(uint32_t*)0x2000006c = 0);
+ NONFAILING(*(uint32_t*)0x20000070 = 0);
+ NONFAILING(*(uint32_t*)0x20000074 = 0);
+ NONFAILING(*(uint32_t*)0x20000078 = 0);
+ NONFAILING(*(uint32_t*)0x2000007c = 0);
+ NONFAILING(*(uint32_t*)0x20000080 = 0);
+ NONFAILING(*(uint32_t*)0x20000084 = 0);
+ NONFAILING(*(uint32_t*)0x20000088 = 0);
+ NONFAILING(*(uint32_t*)0x2000008c = 0);
+ NONFAILING(memcpy(
+ (void*)0x20000090,
+ "\xad\x64\xf3\x09\x91\x77\xc4\x5a\xcb\x83\xba\x06\xc3\xec\x99\x9c\x9c"
+ "\xd2\x26\x49\x2a\xae\xf5\x96\x69\x6e\x86\x1a\x1e\x26\x67\x46\x14\x39"
+ "\xaa\xd7\x17\x17\x3f\x7c\x09\xcc\x6e\xdc\x02\x23\x78\x32\xfd\x21\x09"
+ "\xee\x98\x1b\xd8\x17\x90\x94\xdd\x20\x1f\xd8\xf4\x37\x44\xa1\x31\x0c"
+ "\x97\x29\x46\xa8\x66\xab\x9e\x15\xe1\x88\xf5\x7d\x08\x2e\xdf\xc7\x97"
+ "\xd0\xd5\xa7\xaa\x73\x25\x3b\xac\x0d\x44\x86\xb8\x45\x08\x58\x2c\x5d"
+ "\x2d\xb2\xa7\x46\x58\xe9\x6f\x83\xd9\xfa\xb3\x78\x94\x61\x9d\x44\xdf"
+ "\xf2\x7e\x47\xe6\xda\xaf\xb5\xca\xa5\x76\xa4\x27\x8c\xbc\xca\x41\xfd"
+ "\xd9\xc1\x6c\x01\xc9\x25\xaf\x4f\x3a\xcb\x71\x0b\x8c\xc1\x38\xbe\x9f"
+ "\xd3\x40\xd7\xc9\x6a\x12\x35\x5b\xe9\x4f\xa0\x16\xe8\x53\x8e\xb9\x13"
+ "\xf9\xad\x5a\xb8\xc0\x8b\x7e\x35\x3a\xc7\xde\x00\xac\xbc\x58\x5b\x8f"
+ "\xb6\xb6\x01\xe3\x16\xba\xd9\x90\x34\xb6\x8d\x44\xb2\x94\x9d\x94\x9e"
+ "\x78\x70\xde\x11\x0f\xdd\x14\x2f\x66\x0e\x2b\x7e\x99\x51\x2c\x26\x31"
+ "\x2c\x68\xb1\xfc\xa7\xa6\xba\xb2\xed\xcc\x13\x62\x69",
+ 234));
+ syscall(__NR_ioctl, r[0], 0xc0506617ul, 0x20000040ul);
+ break;
+ case 2:
+ syscall(__NR_ioctl, r[0], 0x4b69ul, 0x20000180ul);
+ break;
+ case 3:
+ NONFAILING(memcpy((void*)0x20000200, "/dev/vcsu#\000", 11));
+ res = syz_open_dev(0x20000200, 8, 0x1400);
+ if (res != -1)
+ r[1] = res;
+ break;
+ case 4:
+ NONFAILING(*(uint32_t*)0x20000240 = 0x10);
+ NONFAILING(*(uint32_t*)0x20000244 = 2);
+ syscall(__NR_ioctl, r[1], 0x4610ul, 0x20000240ul);
+ break;
+ case 5:
+ res = syz_open_dev(0, 0xffff, 0x40c0);
+ if (res != -1)
+ r[2] = res;
+ break;
+ case 6:
+ NONFAILING(*(uint16_t*)0x200002c0 = 0);
+ NONFAILING(*(uint16_t*)0x200002c2 = 1);
+ NONFAILING(*(uint64_t*)0x200002c8 = 7);
+ NONFAILING(*(uint64_t*)0x200002d0 = 6);
+ NONFAILING(*(uint32_t*)0x200002d8 = 0);
+ NONFAILING(*(uint32_t*)0x200002dc = 0);
+ NONFAILING(*(uint32_t*)0x200002e0 = 0);
+ NONFAILING(*(uint32_t*)0x200002e4 = 0);
+ NONFAILING(*(uint32_t*)0x200002e8 = 0);
+ NONFAILING(*(uint32_t*)0x200002ec = 0);
+ syscall(__NR_ioctl, r[2], 0x40305828ul, 0x200002c0ul);
+ break;
+ case 7:
+ NONFAILING(memcpy((void*)0x20000300, "/dev/fb0\000", 9));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000300ul, 0x101000ul,
+ 0ul);
+ if (res != -1)
+ r[3] = res;
+ break;
+ case 8:
+ NONFAILING(*(uint32_t*)0x20000340 = 0x36);
+ NONFAILING(*(uint32_t*)0x20000344 = 0);
+ syscall(__NR_ioctl, r[3], 0x460ful, 0x20000340ul);
+ break;
+ case 9:
+ res = syscall(__NR_ioctl, r[0], 0x5441ul, 0xfffffffffffff800ul);
+ if (res != -1)
+ r[4] = res;
+ break;
+ case 10:
+ syscall(__NR_ioctl, r[4], 0x5429ul, 0x20000380ul);
+ break;
+ case 11:
+ NONFAILING(memcpy((void*)0x200003c0, "/dev/vcsu#\000", 11));
+ res = syz_open_dev(0x200003c0, 9, 0x400000);
+ if (res != -1)
+ r[5] = res;
+ break;
+ case 12:
+ NONFAILING(*(uint32_t*)0x20000400 = 0);
+ NONFAILING(*(uint32_t*)0x20000404 = 0);
+ NONFAILING(*(uint32_t*)0x20000408 = 4);
+ NONFAILING(*(uint32_t*)0x2000040c = 0);
+ NONFAILING(*(uint64_t*)0x20000410 = 0);
+ NONFAILING(*(uint64_t*)0x20000418 = 0);
+ NONFAILING(*(uint64_t*)0x20000420 = 0);
+ NONFAILING(*(uint64_t*)0x20000428 = 0);
+ NONFAILING(*(uint64_t*)0x20000430 = 0);
+ NONFAILING(*(uint64_t*)0x20000438 = 0);
+ NONFAILING(*(uint32_t*)0x20000440 = 2);
+ NONFAILING(*(uint32_t*)0x20000444 = 0x81);
+ NONFAILING(*(uint64_t*)0x20000448 = 0x1ff);
+ NONFAILING(*(uint64_t*)0x20000450 = 8);
+ NONFAILING(*(uint64_t*)0x20000458 = 0x200000);
+ NONFAILING(*(uint64_t*)0x20000460 = 0);
+ NONFAILING(*(uint64_t*)0x20000468 = 0);
+ NONFAILING(*(uint64_t*)0x20000470 = 0);
+ NONFAILING(*(uint64_t*)0x20000478 = 0);
+ NONFAILING(*(uint32_t*)0x20000480 = 0x1f);
+ NONFAILING(*(uint32_t*)0x20000484 = 6);
+ NONFAILING(*(uint64_t*)0x20000488 = 4);
+ NONFAILING(*(uint64_t*)0x20000490 = 2);
+ NONFAILING(*(uint64_t*)0x20000498 = 4);
+ NONFAILING(*(uint64_t*)0x200004a0 = 1);
+ NONFAILING(*(uint64_t*)0x200004a8 = 0);
+ NONFAILING(*(uint64_t*)0x200004b0 = 0);
+ NONFAILING(*(uint64_t*)0x200004b8 = 0);
+ NONFAILING(*(uint8_t*)0x200004c0 = 0);
+ NONFAILING(*(uint8_t*)0x200004c1 = 0);
+ NONFAILING(*(uint8_t*)0x200004c2 = 0);
+ NONFAILING(*(uint8_t*)0x200004c3 = 0);
+ NONFAILING(*(uint8_t*)0x200004c4 = 0);
+ NONFAILING(*(uint8_t*)0x200004c5 = 0);
+ NONFAILING(*(uint8_t*)0x200004c6 = 0);
+ NONFAILING(*(uint8_t*)0x200004c7 = 0);
+ NONFAILING(*(uint8_t*)0x200004c8 = 0);
+ NONFAILING(*(uint8_t*)0x200004c9 = 0);
+ NONFAILING(*(uint8_t*)0x200004ca = 0);
+ NONFAILING(*(uint8_t*)0x200004cb = 0);
+ NONFAILING(*(uint8_t*)0x200004cc = 0);
+ NONFAILING(*(uint8_t*)0x200004cd = 0);
+ NONFAILING(*(uint8_t*)0x200004ce = 0);
+ NONFAILING(*(uint8_t*)0x200004cf = 0);
+ NONFAILING(*(uint8_t*)0x200004d0 = 0);
+ NONFAILING(*(uint8_t*)0x200004d1 = 0);
+ NONFAILING(*(uint8_t*)0x200004d2 = 0);
+ NONFAILING(*(uint8_t*)0x200004d3 = 0);
+ NONFAILING(*(uint8_t*)0x200004d4 = 0);
+ NONFAILING(*(uint8_t*)0x200004d5 = 0);
+ NONFAILING(*(uint8_t*)0x200004d6 = 0);
+ NONFAILING(*(uint8_t*)0x200004d7 = 0);
+ NONFAILING(*(uint8_t*)0x200004d8 = 0);
+ NONFAILING(*(uint8_t*)0x200004d9 = 0);
+ NONFAILING(*(uint8_t*)0x200004da = 0);
+ NONFAILING(*(uint8_t*)0x200004db = 0);
+ NONFAILING(*(uint8_t*)0x200004dc = 0);
+ NONFAILING(*(uint8_t*)0x200004dd = 0);
+ NONFAILING(*(uint8_t*)0x200004de = 0);
+ NONFAILING(*(uint8_t*)0x200004df = 0);
+ NONFAILING(*(uint8_t*)0x200004e0 = 0);
+ NONFAILING(*(uint8_t*)0x200004e1 = 0);
+ NONFAILING(*(uint8_t*)0x200004e2 = 0);
+ NONFAILING(*(uint8_t*)0x200004e3 = 0);
+ NONFAILING(*(uint8_t*)0x200004e4 = 0);
+ NONFAILING(*(uint8_t*)0x200004e5 = 0);
+ NONFAILING(*(uint8_t*)0x200004e6 = 0);
+ NONFAILING(*(uint8_t*)0x200004e7 = 0);
+ NONFAILING(*(uint8_t*)0x200004e8 = 0);
+ NONFAILING(*(uint8_t*)0x200004e9 = 0);
+ NONFAILING(*(uint8_t*)0x200004ea = 0);
+ NONFAILING(*(uint8_t*)0x200004eb = 0);
+ NONFAILING(*(uint8_t*)0x200004ec = 0);
+ NONFAILING(*(uint8_t*)0x200004ed = 0);
+ NONFAILING(*(uint8_t*)0x200004ee = 0);
+ NONFAILING(*(uint8_t*)0x200004ef = 0);
+ NONFAILING(*(uint8_t*)0x200004f0 = 0);
+ NONFAILING(*(uint8_t*)0x200004f1 = 0);
+ NONFAILING(*(uint8_t*)0x200004f2 = 0);
+ NONFAILING(*(uint8_t*)0x200004f3 = 0);
+ NONFAILING(*(uint8_t*)0x200004f4 = 0);
+ NONFAILING(*(uint8_t*)0x200004f5 = 0);
+ NONFAILING(*(uint8_t*)0x200004f6 = 0);
+ NONFAILING(*(uint8_t*)0x200004f7 = 0);
+ NONFAILING(*(uint8_t*)0x200004f8 = 0);
+ NONFAILING(*(uint8_t*)0x200004f9 = 0);
+ NONFAILING(*(uint8_t*)0x200004fa = 0);
+ NONFAILING(*(uint8_t*)0x200004fb = 0);
+ NONFAILING(*(uint8_t*)0x200004fc = 0);
+ NONFAILING(*(uint8_t*)0x200004fd = 0);
+ NONFAILING(*(uint8_t*)0x200004fe = 0);
+ NONFAILING(*(uint8_t*)0x200004ff = 0);
+ NONFAILING(*(uint8_t*)0x20000500 = 0);
+ NONFAILING(*(uint8_t*)0x20000501 = 0);
+ NONFAILING(*(uint8_t*)0x20000502 = 0);
+ NONFAILING(*(uint8_t*)0x20000503 = 0);
+ NONFAILING(*(uint8_t*)0x20000504 = 0);
+ NONFAILING(*(uint8_t*)0x20000505 = 0);
+ NONFAILING(*(uint8_t*)0x20000506 = 0);
+ NONFAILING(*(uint8_t*)0x20000507 = 0);
+ NONFAILING(*(uint8_t*)0x20000508 = 0);
+ NONFAILING(*(uint8_t*)0x20000509 = 0);
+ NONFAILING(*(uint8_t*)0x2000050a = 0);
+ NONFAILING(*(uint8_t*)0x2000050b = 0);
+ NONFAILING(*(uint8_t*)0x2000050c = 0);
+ NONFAILING(*(uint8_t*)0x2000050d = 0);
+ NONFAILING(*(uint8_t*)0x2000050e = 0);
+ NONFAILING(*(uint8_t*)0x2000050f = 0);
+ NONFAILING(*(uint8_t*)0x20000510 = 0);
+ NONFAILING(*(uint8_t*)0x20000511 = 0);
+ NONFAILING(*(uint8_t*)0x20000512 = 0);
+ NONFAILING(*(uint8_t*)0x20000513 = 0);
+ NONFAILING(*(uint8_t*)0x20000514 = 0);
+ NONFAILING(*(uint8_t*)0x20000515 = 0);
+ NONFAILING(*(uint8_t*)0x20000516 = 0);
+ NONFAILING(*(uint8_t*)0x20000517 = 0);
+ NONFAILING(*(uint8_t*)0x20000518 = 0);
+ NONFAILING(*(uint8_t*)0x20000519 = 0);
+ NONFAILING(*(uint8_t*)0x2000051a = 0);
+ NONFAILING(*(uint8_t*)0x2000051b = 0);
+ NONFAILING(*(uint8_t*)0x2000051c = 0);
+ NONFAILING(*(uint8_t*)0x2000051d = 0);
+ NONFAILING(*(uint8_t*)0x2000051e = 0);
+ NONFAILING(*(uint8_t*)0x2000051f = 0);
+ NONFAILING(*(uint8_t*)0x20000520 = 0);
+ NONFAILING(*(uint8_t*)0x20000521 = 0);
+ NONFAILING(*(uint8_t*)0x20000522 = 0);
+ NONFAILING(*(uint8_t*)0x20000523 = 0);
+ NONFAILING(*(uint8_t*)0x20000524 = 0);
+ NONFAILING(*(uint8_t*)0x20000525 = 0);
+ NONFAILING(*(uint8_t*)0x20000526 = 0);
+ NONFAILING(*(uint8_t*)0x20000527 = 0);
+ NONFAILING(*(uint8_t*)0x20000528 = 0);
+ NONFAILING(*(uint8_t*)0x20000529 = 0);
+ NONFAILING(*(uint8_t*)0x2000052a = 0);
+ NONFAILING(*(uint8_t*)0x2000052b = 0);
+ NONFAILING(*(uint8_t*)0x2000052c = 0);
+ NONFAILING(*(uint8_t*)0x2000052d = 0);
+ NONFAILING(*(uint8_t*)0x2000052e = 0);
+ NONFAILING(*(uint8_t*)0x2000052f = 0);
+ NONFAILING(*(uint8_t*)0x20000530 = 0);
+ NONFAILING(*(uint8_t*)0x20000531 = 0);
+ NONFAILING(*(uint8_t*)0x20000532 = 0);
+ NONFAILING(*(uint8_t*)0x20000533 = 0);
+ NONFAILING(*(uint8_t*)0x20000534 = 0);
+ NONFAILING(*(uint8_t*)0x20000535 = 0);
+ NONFAILING(*(uint8_t*)0x20000536 = 0);
+ NONFAILING(*(uint8_t*)0x20000537 = 0);
+ NONFAILING(*(uint8_t*)0x20000538 = 0);
+ NONFAILING(*(uint8_t*)0x20000539 = 0);
+ NONFAILING(*(uint8_t*)0x2000053a = 0);
+ NONFAILING(*(uint8_t*)0x2000053b = 0);
+ NONFAILING(*(uint8_t*)0x2000053c = 0);
+ NONFAILING(*(uint8_t*)0x2000053d = 0);
+ NONFAILING(*(uint8_t*)0x2000053e = 0);
+ NONFAILING(*(uint8_t*)0x2000053f = 0);
+ NONFAILING(*(uint8_t*)0x20000540 = 0);
+ NONFAILING(*(uint8_t*)0x20000541 = 0);
+ NONFAILING(*(uint8_t*)0x20000542 = 0);
+ NONFAILING(*(uint8_t*)0x20000543 = 0);
+ NONFAILING(*(uint8_t*)0x20000544 = 0);
+ NONFAILING(*(uint8_t*)0x20000545 = 0);
+ NONFAILING(*(uint8_t*)0x20000546 = 0);
+ NONFAILING(*(uint8_t*)0x20000547 = 0);
+ NONFAILING(*(uint8_t*)0x20000548 = 0);
+ NONFAILING(*(uint8_t*)0x20000549 = 0);
+ NONFAILING(*(uint8_t*)0x2000054a = 0);
+ NONFAILING(*(uint8_t*)0x2000054b = 0);
+ NONFAILING(*(uint8_t*)0x2000054c = 0);
+ NONFAILING(*(uint8_t*)0x2000054d = 0);
+ NONFAILING(*(uint8_t*)0x2000054e = 0);
+ NONFAILING(*(uint8_t*)0x2000054f = 0);
+ NONFAILING(*(uint8_t*)0x20000550 = 0);
+ NONFAILING(*(uint8_t*)0x20000551 = 0);
+ NONFAILING(*(uint8_t*)0x20000552 = 0);
+ NONFAILING(*(uint8_t*)0x20000553 = 0);
+ NONFAILING(*(uint8_t*)0x20000554 = 0);
+ NONFAILING(*(uint8_t*)0x20000555 = 0);
+ NONFAILING(*(uint8_t*)0x20000556 = 0);
+ NONFAILING(*(uint8_t*)0x20000557 = 0);
+ NONFAILING(*(uint8_t*)0x20000558 = 0);
+ NONFAILING(*(uint8_t*)0x20000559 = 0);
+ NONFAILING(*(uint8_t*)0x2000055a = 0);
+ NONFAILING(*(uint8_t*)0x2000055b = 0);
+ NONFAILING(*(uint8_t*)0x2000055c = 0);
+ NONFAILING(*(uint8_t*)0x2000055d = 0);
+ NONFAILING(*(uint8_t*)0x2000055e = 0);
+ NONFAILING(*(uint8_t*)0x2000055f = 0);
+ NONFAILING(*(uint8_t*)0x20000560 = 0);
+ NONFAILING(*(uint8_t*)0x20000561 = 0);
+ NONFAILING(*(uint8_t*)0x20000562 = 0);
+ NONFAILING(*(uint8_t*)0x20000563 = 0);
+ NONFAILING(*(uint8_t*)0x20000564 = 0);
+ NONFAILING(*(uint8_t*)0x20000565 = 0);
+ NONFAILING(*(uint8_t*)0x20000566 = 0);
+ NONFAILING(*(uint8_t*)0x20000567 = 0);
+ NONFAILING(*(uint8_t*)0x20000568 = 0);
+ NONFAILING(*(uint8_t*)0x20000569 = 0);
+ NONFAILING(*(uint8_t*)0x2000056a = 0);
+ NONFAILING(*(uint8_t*)0x2000056b = 0);
+ NONFAILING(*(uint8_t*)0x2000056c = 0);
+ NONFAILING(*(uint8_t*)0x2000056d = 0);
+ NONFAILING(*(uint8_t*)0x2000056e = 0);
+ NONFAILING(*(uint8_t*)0x2000056f = 0);
+ NONFAILING(*(uint8_t*)0x20000570 = 0);
+ NONFAILING(*(uint8_t*)0x20000571 = 0);
+ NONFAILING(*(uint8_t*)0x20000572 = 0);
+ NONFAILING(*(uint8_t*)0x20000573 = 0);
+ NONFAILING(*(uint8_t*)0x20000574 = 0);
+ NONFAILING(*(uint8_t*)0x20000575 = 0);
+ NONFAILING(*(uint8_t*)0x20000576 = 0);
+ NONFAILING(*(uint8_t*)0x20000577 = 0);
+ NONFAILING(*(uint8_t*)0x20000578 = 0);
+ NONFAILING(*(uint8_t*)0x20000579 = 0);
+ NONFAILING(*(uint8_t*)0x2000057a = 0);
+ NONFAILING(*(uint8_t*)0x2000057b = 0);
+ NONFAILING(*(uint8_t*)0x2000057c = 0);
+ NONFAILING(*(uint8_t*)0x2000057d = 0);
+ NONFAILING(*(uint8_t*)0x2000057e = 0);
+ NONFAILING(*(uint8_t*)0x2000057f = 0);
+ NONFAILING(*(uint8_t*)0x20000580 = 0);
+ NONFAILING(*(uint8_t*)0x20000581 = 0);
+ NONFAILING(*(uint8_t*)0x20000582 = 0);
+ NONFAILING(*(uint8_t*)0x20000583 = 0);
+ NONFAILING(*(uint8_t*)0x20000584 = 0);
+ NONFAILING(*(uint8_t*)0x20000585 = 0);
+ NONFAILING(*(uint8_t*)0x20000586 = 0);
+ NONFAILING(*(uint8_t*)0x20000587 = 0);
+ NONFAILING(*(uint8_t*)0x20000588 = 0);
+ NONFAILING(*(uint8_t*)0x20000589 = 0);
+ NONFAILING(*(uint8_t*)0x2000058a = 0);
+ NONFAILING(*(uint8_t*)0x2000058b = 0);
+ NONFAILING(*(uint8_t*)0x2000058c = 0);
+ NONFAILING(*(uint8_t*)0x2000058d = 0);
+ NONFAILING(*(uint8_t*)0x2000058e = 0);
+ NONFAILING(*(uint8_t*)0x2000058f = 0);
+ NONFAILING(*(uint8_t*)0x20000590 = 0);
+ NONFAILING(*(uint8_t*)0x20000591 = 0);
+ NONFAILING(*(uint8_t*)0x20000592 = 0);
+ NONFAILING(*(uint8_t*)0x20000593 = 0);
+ NONFAILING(*(uint8_t*)0x20000594 = 0);
+ NONFAILING(*(uint8_t*)0x20000595 = 0);
+ NONFAILING(*(uint8_t*)0x20000596 = 0);
+ NONFAILING(*(uint8_t*)0x20000597 = 0);
+ NONFAILING(*(uint8_t*)0x20000598 = 0);
+ NONFAILING(*(uint8_t*)0x20000599 = 0);
+ NONFAILING(*(uint8_t*)0x2000059a = 0);
+ NONFAILING(*(uint8_t*)0x2000059b = 0);
+ NONFAILING(*(uint8_t*)0x2000059c = 0);
+ NONFAILING(*(uint8_t*)0x2000059d = 0);
+ NONFAILING(*(uint8_t*)0x2000059e = 0);
+ NONFAILING(*(uint8_t*)0x2000059f = 0);
+ NONFAILING(*(uint8_t*)0x200005a0 = 0);
+ NONFAILING(*(uint8_t*)0x200005a1 = 0);
+ NONFAILING(*(uint8_t*)0x200005a2 = 0);
+ NONFAILING(*(uint8_t*)0x200005a3 = 0);
+ NONFAILING(*(uint8_t*)0x200005a4 = 0);
+ NONFAILING(*(uint8_t*)0x200005a5 = 0);
+ NONFAILING(*(uint8_t*)0x200005a6 = 0);
+ NONFAILING(*(uint8_t*)0x200005a7 = 0);
+ NONFAILING(*(uint8_t*)0x200005a8 = 0);
+ NONFAILING(*(uint8_t*)0x200005a9 = 0);
+ NONFAILING(*(uint8_t*)0x200005aa = 0);
+ NONFAILING(*(uint8_t*)0x200005ab = 0);
+ NONFAILING(*(uint8_t*)0x200005ac = 0);
+ NONFAILING(*(uint8_t*)0x200005ad = 0);
+ NONFAILING(*(uint8_t*)0x200005ae = 0);
+ NONFAILING(*(uint8_t*)0x200005af = 0);
+ NONFAILING(*(uint8_t*)0x200005b0 = 0);
+ NONFAILING(*(uint8_t*)0x200005b1 = 0);
+ NONFAILING(*(uint8_t*)0x200005b2 = 0);
+ NONFAILING(*(uint8_t*)0x200005b3 = 0);
+ NONFAILING(*(uint8_t*)0x200005b4 = 0);
+ NONFAILING(*(uint8_t*)0x200005b5 = 0);
+ NONFAILING(*(uint8_t*)0x200005b6 = 0);
+ NONFAILING(*(uint8_t*)0x200005b7 = 0);
+ NONFAILING(*(uint8_t*)0x200005b8 = 0);
+ NONFAILING(*(uint8_t*)0x200005b9 = 0);
+ NONFAILING(*(uint8_t*)0x200005ba = 0);
+ NONFAILING(*(uint8_t*)0x200005bb = 0);
+ NONFAILING(*(uint8_t*)0x200005bc = 0);
+ NONFAILING(*(uint8_t*)0x200005bd = 0);
+ NONFAILING(*(uint8_t*)0x200005be = 0);
+ NONFAILING(*(uint8_t*)0x200005bf = 0);
+ syscall(__NR_ioctl, r[5], 0xc0c0583bul, 0x20000400ul);
+ break;
+ case 13:
+ NONFAILING(*(uint32_t*)0x200005c0 = 1);
+ NONFAILING(*(uint32_t*)0x200005c4 = 9);
+ syscall(__NR_ioctl, r[4], 0x4b4cul, 0x200005c0ul);
+ break;
+ case 14:
+ NONFAILING(*(uint8_t*)0x20000600 = 5);
+ NONFAILING(*(uint64_t*)0x20000601 = 2);
+ NONFAILING(*(uint64_t*)0x20000609 = 4);
+ NONFAILING(*(uint64_t*)0x20000611 = 0x80000001);
+ NONFAILING(*(uint64_t*)0x20000619 = 8);
+ syscall(__NR_ioctl, r[5], 0x541cul, 0x20000600ul);
+ break;
+ case 15:
+ syscall(__NR_ioctl, -1, 0x81009431ul, 0x20000640ul);
+ break;
+ case 16:
+ res = syscall(__NR_ioctl, r[4], 0x5441ul, 0x100000000ul);
+ if (res != -1)
+ r[6] = res;
+ break;
+ case 17:
+ NONFAILING(*(uint32_t*)0x20000740 = 2);
+ syscall(__NR_ioctl, r[6], 1ul, 0x20000740ul);
+ break;
+ case 18:
+ NONFAILING(memcpy((void*)0x20000780, "/dev/input/event#\000", 18));
+ res = syz_open_dev(0x20000780, 0x1ff, 0x8000);
+ if (res != -1)
+ r[7] = res;
+ break;
+ case 19:
+ syscall(__NR_ioctl, r[7], 0x8040451aul, 0x200007c0ul);
+ break;
+ case 20:
+ NONFAILING(memcpy((void*)0x20000800, "/dev/vcsu#\000", 11));
+ res = syz_open_dev(0x20000800, 0x2d, 0x909042);
+ if (res != -1)
+ r[8] = res;
+ break;
+ case 21:
+ NONFAILING(*(uint64_t*)0x20000840 = 0xa99d);
+ NONFAILING(*(uint64_t*)0x20000848 = 3);
+ NONFAILING(*(uint32_t*)0x20000850 = 6);
+ NONFAILING(*(uint32_t*)0x20000854 = 0x68);
+ NONFAILING(*(uint32_t*)0x20000858 = 6);
+ NONFAILING(*(uint64_t*)0x20000860 = 0x8000);
+ NONFAILING(*(uint64_t*)0x20000868 = 6);
+ NONFAILING(*(uint64_t*)0x20000870 = 0x20);
+ NONFAILING(*(uint64_t*)0x20000878 = 0);
+ NONFAILING(*(uint64_t*)0x20000880 = 0);
+ NONFAILING(*(uint32_t*)0x20000888 = 0x80);
+ NONFAILING(*(uint32_t*)0x2000088c = 0);
+ NONFAILING(*(uint32_t*)0x20000890 = 0);
+ NONFAILING(*(uint32_t*)0x20000894 = 0);
+ NONFAILING(*(uint64_t*)0x20000898 = 0xffffffff);
+ NONFAILING(*(uint64_t*)0x200008a0 = 0xc2);
+ NONFAILING(*(uint64_t*)0x200008a8 = 0x8000);
+ NONFAILING(*(uint64_t*)0x200008b0 = 0);
+ NONFAILING(*(uint64_t*)0x200008b8 = 0);
+ NONFAILING(*(uint32_t*)0x200008c0 = 0x100);
+ NONFAILING(*(uint32_t*)0x200008c4 = 0);
+ NONFAILING(*(uint32_t*)0x200008c8 = 0);
+ NONFAILING(*(uint32_t*)0x200008cc = 0);
+ NONFAILING(*(uint64_t*)0x200008d0 = 0x80);
+ NONFAILING(*(uint64_t*)0x200008d8 = 1);
+ NONFAILING(*(uint64_t*)0x200008e0 = 7);
+ NONFAILING(*(uint64_t*)0x200008e8 = 0);
+ NONFAILING(*(uint64_t*)0x200008f0 = 0);
+ NONFAILING(*(uint32_t*)0x200008f8 = 8);
+ NONFAILING(*(uint32_t*)0x200008fc = 0);
+ NONFAILING(*(uint32_t*)0x20000900 = 0);
+ NONFAILING(*(uint32_t*)0x20000904 = 0);
+ NONFAILING(*(uint64_t*)0x20000908 = 1);
+ NONFAILING(*(uint64_t*)0x20000910 = 0xffff);
+ NONFAILING(*(uint64_t*)0x20000918 = 9);
+ NONFAILING(*(uint64_t*)0x20000920 = 0);
+ NONFAILING(*(uint64_t*)0x20000928 = 0);
+ NONFAILING(*(uint32_t*)0x20000930 = 2);
+ NONFAILING(*(uint32_t*)0x20000934 = 0);
+ NONFAILING(*(uint32_t*)0x20000938 = 0);
+ NONFAILING(*(uint32_t*)0x2000093c = 0);
+ NONFAILING(*(uint64_t*)0x20000940 = 0xffffffff);
+ NONFAILING(*(uint64_t*)0x20000948 = 0x1ff);
+ NONFAILING(*(uint64_t*)0x20000950 = 0);
+ NONFAILING(*(uint64_t*)0x20000958 = 0);
+ NONFAILING(*(uint64_t*)0x20000960 = 0);
+ NONFAILING(*(uint32_t*)0x20000968 = 0x200);
+ NONFAILING(*(uint32_t*)0x2000096c = 0);
+ NONFAILING(*(uint32_t*)0x20000970 = 0);
+ NONFAILING(*(uint32_t*)0x20000974 = 0);
+ NONFAILING(*(uint64_t*)0x20000978 = 6);
+ NONFAILING(*(uint64_t*)0x20000980 = 0x10001);
+ NONFAILING(*(uint64_t*)0x20000988 = 1);
+ NONFAILING(*(uint64_t*)0x20000990 = 0);
+ NONFAILING(*(uint64_t*)0x20000998 = 0);
+ NONFAILING(*(uint32_t*)0x200009a0 = 0x400);
+ NONFAILING(*(uint32_t*)0x200009a4 = 0);
+ NONFAILING(*(uint32_t*)0x200009a8 = 0);
+ NONFAILING(*(uint32_t*)0x200009ac = 0);
+ syscall(__NR_ioctl, r[8], 0xc020660bul, 0x20000840ul);
+ break;
+ case 22:
+ NONFAILING(memcpy((void*)0x200009c0, "/dev/vcsa#\000", 11));
+ syz_open_dev(0x200009c0, 0x1ff, 0xa000);
+ break;
+ case 23:
+ NONFAILING(memcpy((void*)0x20000a00, "/dev/vcsu#\000", 11));
+ res = syz_open_dev(0x20000a00, 6, 0x12000);
+ if (res != -1)
+ r[9] = res;
+ break;
+ case 24:
+ NONFAILING(memcpy((void*)0x20000a40, "/dev/vcsu#\000", 11));
+ res = syz_open_dev(0x20000a40, 2, 0x200);
+ if (res != -1)
+ r[10] = res;
+ break;
+ case 25:
+ NONFAILING(*(uint64_t*)0x20000a80 = 9);
+ NONFAILING(*(uint64_t*)0x20000a88 = 0x4217);
+ NONFAILING(*(uint16_t*)0x20000a90 = 1);
+ NONFAILING(*(uint16_t*)0x20000a92 = 0);
+ NONFAILING(*(uint32_t*)0x20000a94 = 0);
+ NONFAILING(*(uint32_t*)0x20000a98 = r[10]);
+ NONFAILING(*(uint32_t*)0x20000a9c = 0);
+ NONFAILING(*(uint64_t*)0x20000aa0 = 0x7ff);
+ NONFAILING(*(uint64_t*)0x20000aa8 = 0);
+ NONFAILING(*(uint32_t*)0x20000ab0 = 0);
+ NONFAILING(*(uint32_t*)0x20000ab4 = 0);
+ syscall(__NR_ioctl, r[9], 0xc0189436ul, 0x20000a80ul);
+ break;
+ case 26:
+ syscall(__NR_ioctl, r[2], 0x4b3aul, 1ul);
+ break;
+ case 27:
+ NONFAILING(memcpy((void*)0x20000ac0, "/dev/vcsu#\000", 11));
+ res = syz_open_dev(0x20000ac0, 0x20, 0x200240);
+ if (res != -1)
+ r[11] = res;
+ break;
+ case 28:
+ syscall(__NR_ioctl, r[11], 0x5415ul, 0x20000b00ul);
+ break;
+ case 29:
+ NONFAILING(memcpy((void*)0x20000b40, "/dev/vcsa#\000", 11));
+ res = syz_open_dev(0x20000b40, 0x101, 0);
+ if (res != -1)
+ r[12] = res;
+ break;
+ case 30:
+ NONFAILING(*(uint64_t*)0x20000b80 = 9);
+ NONFAILING(*(uint64_t*)0x20000b88 = 9);
+ NONFAILING(*(uint64_t*)0x20000b90 = 2);
+ syscall(__NR_ioctl, r[12], 0xc0185879ul, 0x20000b80ul);
+ break;
+ case 31:
+ syscall(__NR_read, -1, 0x20000100ul, 0x1eul);
+ break;
+ case 32:
+ NONFAILING(memcpy((void*)0x20000000, "/dev/fb0\000", 9));
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+ if (res != -1)
+ r[13] = res;
+ break;
+ case 33:
+ NONFAILING(*(uint32_t*)0x20000040 = 0);
+ NONFAILING(*(uint32_t*)0x20000044 = 0);
+ NONFAILING(*(uint32_t*)0x20000048 = 0);
+ NONFAILING(*(uint32_t*)0x2000004c = 0);
+ NONFAILING(*(uint32_t*)0x20000050 = 0);
+ NONFAILING(*(uint32_t*)0x20000054 = 0);
+ NONFAILING(*(uint32_t*)0x20000058 = 0x20);
+ NONFAILING(*(uint32_t*)0x2000005c = 0);
+ NONFAILING(*(uint32_t*)0x20000060 = 0);
+ NONFAILING(*(uint32_t*)0x20000064 = 0);
+ NONFAILING(*(uint32_t*)0x20000068 = 0);
+ NONFAILING(*(uint32_t*)0x2000006c = 0);
+ NONFAILING(*(uint32_t*)0x20000070 = 0);
+ NONFAILING(*(uint32_t*)0x20000074 = 0);
+ NONFAILING(*(uint32_t*)0x20000078 = 0);
+ NONFAILING(*(uint32_t*)0x2000007c = 0);
+ NONFAILING(*(uint32_t*)0x20000080 = 0);
+ NONFAILING(*(uint32_t*)0x20000084 = 0);
+ NONFAILING(*(uint32_t*)0x20000088 = 0);
+ NONFAILING(*(uint32_t*)0x2000008c = 0);
+ NONFAILING(*(uint32_t*)0x20000090 = 0);
+ NONFAILING(*(uint32_t*)0x20000094 = 0x40);
+ NONFAILING(*(uint32_t*)0x20000098 = 0);
+ NONFAILING(*(uint32_t*)0x2000009c = 0);
+ NONFAILING(*(uint32_t*)0x200000a0 = 0);
+ NONFAILING(*(uint32_t*)0x200000a4 = 0);
+ NONFAILING(*(uint32_t*)0x200000a8 = 0);
+ NONFAILING(*(uint32_t*)0x200000ac = 0);
+ NONFAILING(*(uint32_t*)0x200000b0 = 0);
+ NONFAILING(*(uint32_t*)0x200000b4 = 0);
+ NONFAILING(*(uint32_t*)0x200000b8 = 0);
+ NONFAILING(*(uint32_t*)0x200000bc = 0);
+ NONFAILING(*(uint32_t*)0x200000c0 = 0);
+ NONFAILING(*(uint32_t*)0x200000c4 = 0);
+ NONFAILING(*(uint32_t*)0x200000c8 = 0);
+ NONFAILING(*(uint32_t*)0x200000cc = 0);
+ NONFAILING(*(uint32_t*)0x200000d0 = 0);
+ NONFAILING(*(uint32_t*)0x200000d4 = 0);
+ NONFAILING(*(uint32_t*)0x200000d8 = 0);
+ NONFAILING(*(uint32_t*)0x200000dc = 0);
+ syscall(__NR_ioctl, r[13], 0x4601ul, 0x20000040ul);
+ break;
+ case 34:
+ NONFAILING(*(uint32_t*)0x20000000 = 2);
+ NONFAILING(*(uint32_t*)0x20000004 = 0);
+ NONFAILING(*(uint32_t*)0x20000008 = 0);
+ NONFAILING(*(uint32_t*)0x2000000c = 0);
+ NONFAILING(*(uint32_t*)0x20000010 = 0);
+ NONFAILING(*(uint64_t*)0x20000018 = 0);
+ syscall(__NR_ioctl, -1, 0x4b72ul, 0x20000000ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ install_segv_handler();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f8725c52685453f7bc7ca68e1d7abaf7bd01c124.c b/syzkaller-repros/linux/f8725c52685453f7bc7ca68e1d7abaf7bd01c124.c
new file mode 100644
index 0000000..f405b38
--- /dev/null
+++ b/syzkaller-repros/linux/f8725c52685453f7bc7ca68e1d7abaf7bd01c124.c
@@ -0,0 +1,1048 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+ (addr < prog_start || addr > prog_end)) {
+ _longjmp(segv_env, 1);
+ }
+ exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
+ syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+static void netlink_add_neigh(int sock, const char* name, const void* addr,
+ int addrsize, const void* mac, int macsize)
+{
+ struct ndmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ndm_ifindex = if_nametoindex(name);
+ hdr.ndm_state = NUD_PERMANENT;
+ netlink_init(RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ netlink_attr(NDA_DST, addr, addrsize);
+ netlink_attr(NDA_LLADDR, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+#define SYZ_TUN_MAX_PACKET_SIZE 1000
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+ tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (tunfd == -1) {
+ printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+ printf("otherwise fuzzing or reproducing might not work as intended\n");
+ return;
+ }
+ const int kTunFd = 240;
+ if (dup2(tunfd, kTunFd) < 0)
+ exit(1);
+ close(tunfd);
+ tunfd = kTunFd;
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ exit(1);
+ }
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ exit(1);
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ char sysctl[64];
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+ write_file(sysctl, "0");
+ sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+ write_file(sysctl, "0");
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ netlink_add_addr4(sock, TUN_IFACE, LOCAL_IPV4);
+ netlink_add_addr6(sock, TUN_IFACE, LOCAL_IPV6);
+ uint64_t macaddr = REMOTE_MAC;
+ struct in_addr in_addr;
+ inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in_addr, sizeof(in_addr), &macaddr,
+ ETH_ALEN);
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+ netlink_add_neigh(sock, TUN_IFACE, &in6_addr, sizeof(in6_addr), &macaddr,
+ ETH_ALEN);
+ macaddr = LOCAL_MAC;
+ netlink_device_change(sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN);
+ close(sock);
+}
+
+static int read_tun(char* data, int size)
+{
+ if (tunfd < 0)
+ return -1;
+ int rv = read(tunfd, data, size);
+ if (rv < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ if (errno == EBADFD)
+ return -1;
+ exit(1);
+ }
+ return rv;
+}
+
+static void flush_tun()
+{
+ char data[SYZ_TUN_MAX_PACKET_SIZE];
+ while (read_tun(&data[0], sizeof(data)) != -1) {
+ }
+}
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_tun();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+ flush_tun();
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+static void setup_binfmt_misc()
+{
+ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+ }
+ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+ write_file("/proc/sys/fs/binfmt_misc/register",
+ ":syz1:M:1:\x02::./file0:POC");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ NONFAILING(memcpy((void*)0x200000c0, "/dev/ptmx\000", 10));
+ res = syscall(__NR_openat, 0xffffffffffffff9c, 0x200000c0, 0, 0);
+ if (res != -1)
+ r[0] = res;
+ NONFAILING(*(uint32_t*)0x20000040 = 0xf);
+ syscall(__NR_ioctl, r[0], 0x5423, 0x20000040);
+ syscall(__NR_ioctl, r[0], 0x400455c8, 1);
+ NONFAILING(*(uint32_t*)0x20000100 = 0);
+ syscall(__NR_ioctl, r[0], 0x5412, 0x20000100);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_binfmt_misc();
+ setup_leak();
+ install_segv_handler();
+ for (procid = 0; procid < 8; procid++) {
+ if (fork() == 0) {
+ do_sandbox_none();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f8ce2875913eb4d65cd6ece71108d9d8e863469a.c b/syzkaller-repros/linux/f8ce2875913eb4d65cd6ece71108d9d8e863469a.c
new file mode 100644
index 0000000..2e6dbfb
--- /dev/null
+++ b/syzkaller-repros/linux/f8ce2875913eb4d65cd6ece71108d9d8e863469a.c
@@ -0,0 +1,190 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static int inject_fault(int nth)
+{
+ int fd;
+ fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ if (fd == -1)
+ exit(1);
+ char buf[16];
+ sprintf(buf, "%d", nth + 1);
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ exit(1);
+ return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void setup_fault()
+{
+ static struct {
+ const char* file;
+ const char* val;
+ bool fatal;
+ } files[] = {
+ {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
+ {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
+ {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
+ if (!write_file(files[i].file, files[i].val)) {
+ if (files[i].fatal)
+ exit(1);
+ }
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x20000080, "/dev/loop-control\000", 18);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000080ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ syscall(__NR_ioctl, r[0], 0x4c81ul, 0ul);
+ memcpy((void*)0x20000100, "/dev/loop-control\000", 18);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000100ul, 0ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ inject_fault(76);
+ syscall(__NR_ioctl, r[1], 0x4c80ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ setup_fault();
+ loop();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f9b1382ef613844e96f73867e9b946aec9774fd6.c b/syzkaller-repros/linux/f9b1382ef613844e96f73867e9b946aec9774fd6.c
new file mode 100644
index 0000000..48db936
--- /dev/null
+++ b/syzkaller-repros/linux/f9b1382ef613844e96f73867e9b946aec9774fd6.c
@@ -0,0 +1,433 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/in6.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+ const char* dev_name, int netns_fd)
+{
+ struct genlmsghdr genlhdr;
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_RELOAD;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+error:
+ close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ int ret = setns(kInitNetNsFd, 0);
+ if (ret == -1)
+ exit(1);
+ netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+ ret = setns(netns, 0);
+ if (ret == -1)
+ exit(1);
+ close(netns);
+ initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ exit(1);
+ if (dup2(netns, kInitNetNsFd) < 0)
+ exit(1);
+ close(netns);
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_devlink_pci();
+ loop();
+ exit(1);
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void loop(void)
+{
+ intptr_t res = 0;
+ memcpy((void*)0x200000c0, "/dev/ptmx\000", 10);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200000c0ul, 0ul, 0ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint32_t*)0x20000040 = 0xf;
+ syscall(__NR_ioctl, r[0], 0x5423ul, 0x20000040ul);
+ syscall(__NR_ioctl, r[0], 0x400455c8ul, 4ul);
+ memcpy((void*)0x20001540, "/dev/ttyprintk\000", 15);
+ res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20001540ul, 0ul, 0ul);
+ if (res != -1)
+ r[1] = res;
+ *(uint32_t*)0x20001580 = 7;
+ syscall(__NR_ioctl, r[1], 0x5423ul, 0x20001580ul);
+ close_fds();
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/f9d67ee369f3db72fa6adaaf0c0000a3b8052d2d.c b/syzkaller-repros/linux/f9d67ee369f3db72fa6adaaf0c0000a3b8052d2d.c
new file mode 100644
index 0000000..012375f
--- /dev/null
+++ b/syzkaller-repros/linux/f9d67ee369f3db72fa6adaaf0c0000a3b8052d2d.c
@@ -0,0 +1,819 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ if (ev->state)
+ exit(1);
+ __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+static void event_wait(event_t* ev)
+{
+ while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
+}
+
+static int event_isset(event_t* ev)
+{
+ return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ for (;;) {
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
+ if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
+ return 1;
+ now = current_time_ms();
+ if (now - start > timeout)
+ return 0;
+ }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static struct {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+} nlmsg;
+
+static void netlink_init(int typ, int flags, const void* data, int size)
+{
+ memset(&nlmsg, 0, sizeof(nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(int typ, const void* data, int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+ attr->nla_type = typ;
+ nlmsg.pos += sizeof(*attr);
+ nlmsg.nested[nlmsg.nesting++] = attr;
+}
+
+static void netlink_done(void)
+{
+ struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+ attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+ if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+ hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+ if (name)
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ netlink_nest(IFLA_LINKINFO);
+ netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+ netlink_add_device_impl(type, name);
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+ netlink_add_device_impl("veth", name);
+ netlink_nest(IFLA_INFO_DATA);
+ netlink_nest(VETH_INFO_PEER);
+ nlmsg.pos += sizeof(struct ifinfomsg);
+ netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+ netlink_done();
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+ const char* slave2)
+{
+ netlink_add_device_impl("hsr", name);
+ netlink_nest(IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done();
+ netlink_done();
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+ const char* master, const void* mac,
+ int macsize)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ netlink_attr(IFLA_IFNAME, name, strlen(name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(sock);
+ (void)err;
+}
+
+static int netlink_add_addr(int sock, const char* dev, const void* addr,
+ int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+ netlink_attr(IFA_LOCAL, addr, addrsize);
+ netlink_attr(IFA_ADDRESS, addr, addrsize);
+ return netlink_send(sock);
+}
+
+static void netlink_add_addr4(int sock, const char* dev, const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(int sock, const char* dev, const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(sock, slave0, false, master, 0, 0);
+ netlink_device_change(sock, slave1, false, master, 0, 0);
+ }
+ netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+ netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+ netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+ }
+ close(sock);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+ if (unshare(CLONE_NEWPID)) {
+ }
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < 30; fd++)
+ close(fd);
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ sleep(5);
+ if (!write_file(KMEMLEAK_FILE, "scan"))
+ exit(1);
+ if (!write_file(KMEMLEAK_FILE, "clear"))
+ exit(1);
+}
+
+static void check_leaks(void)
+{
+ int fd = open(KMEMLEAK_FILE, O_RDWR);
+ if (fd == -1)
+ exit(1);
+ uint64_t start = current_time_ms();
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ sleep(1);
+ while (current_time_ms() - start < 4 * 1000)
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ static char buf[128 << 10];
+ ssize_t n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ int nleaks = 0;
+ if (n != 0) {
+ sleep(1);
+ if (write(fd, "scan", 4) != 4)
+ exit(1);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ exit(1);
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n < 0)
+ exit(1);
+ buf[n] = 0;
+ char* pos = buf;
+ char* end = buf + n;
+ while (pos < end) {
+ char* next = strstr(pos + 1, "unreferenced object");
+ if (!next)
+ next = end;
+ char prev = *next;
+ *next = 0;
+ fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+ *next = prev;
+ pos = next;
+ nleaks++;
+ }
+ }
+ if (write(fd, "clear", 5) != 5)
+ exit(1);
+ close(fd);
+ if (nleaks)
+ exit(1);
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ int i, call, thread;
+ int collide = 0;
+again:
+ for (call = 0; call < 4; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (collide && (call % 2) == 0)
+ break;
+ event_timedwait(&th->done, 45);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+ close_fds();
+ if (!collide) {
+ collide = 1;
+ goto again;
+ }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ int iter;
+ for (iter = 0;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ check_leaks();
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res;
+ switch (call) {
+ case 0:
+ res = syscall(__NR_socket, 2, 3, 0x18);
+ if (res != -1)
+ r[0] = res;
+ break;
+ case 1:
+ *(uint16_t*)0x20000000 = 2;
+ *(uint16_t*)0x20000002 = htobe16(0);
+ *(uint8_t*)0x20000004 = 0xac;
+ *(uint8_t*)0x20000005 = 0x14;
+ *(uint8_t*)0x20000006 = 0x14;
+ *(uint8_t*)0x20000007 = 0xaa;
+ syscall(__NR_connect, -1, 0x20000000, 0x10);
+ break;
+ case 2:
+ *(uint32_t*)0x20000000 = htobe32(0xe0000002);
+ *(uint32_t*)0x20000010 = htobe32(0xe0000001);
+ *(uint16_t*)0x20000020 = htobe16(0);
+ *(uint16_t*)0x20000022 = htobe16(0);
+ *(uint16_t*)0x20000024 = htobe16(0);
+ *(uint16_t*)0x20000026 = htobe16(0);
+ *(uint16_t*)0x20000028 = 0;
+ *(uint8_t*)0x2000002a = 0;
+ *(uint8_t*)0x2000002b = 0;
+ *(uint8_t*)0x2000002c = 0;
+ *(uint32_t*)0x20000030 = 0;
+ *(uint32_t*)0x20000034 = 0;
+ *(uint64_t*)0x20000038 = 0;
+ *(uint64_t*)0x20000040 = 0;
+ *(uint64_t*)0x20000048 = 0;
+ *(uint64_t*)0x20000050 = 0;
+ *(uint64_t*)0x20000058 = 0;
+ *(uint64_t*)0x20000060 = 0;
+ *(uint64_t*)0x20000068 = 0;
+ *(uint64_t*)0x20000070 = 0;
+ *(uint64_t*)0x20000078 = 0;
+ *(uint64_t*)0x20000080 = 0;
+ *(uint64_t*)0x20000088 = 0;
+ *(uint64_t*)0x20000090 = 0;
+ *(uint32_t*)0x20000098 = 0;
+ *(uint32_t*)0x2000009c = 0;
+ *(uint8_t*)0x200000a0 = 0;
+ *(uint8_t*)0x200000a1 = 0;
+ *(uint8_t*)0x200000a2 = 0;
+ *(uint8_t*)0x200000a3 = 0;
+ memcpy((void*)0x200000a8,
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
+ 16);
+ *(uint32_t*)0x200000b8 = htobe32(0);
+ *(uint8_t*)0x200000bc = 0;
+ *(uint16_t*)0x200000c0 = 0;
+ *(uint64_t*)0x200000c4 = htobe64(0);
+ *(uint64_t*)0x200000cc = htobe64(1);
+ *(uint32_t*)0x200000d4 = 0;
+ *(uint8_t*)0x200000d8 = 0;
+ *(uint8_t*)0x200000d9 = 0;
+ *(uint8_t*)0x200000da = 0;
+ *(uint32_t*)0x200000dc = 0;
+ *(uint32_t*)0x200000e0 = 0;
+ *(uint32_t*)0x200000e4 = 0;
+ syscall(__NR_setsockopt, r[0], 0, 0x23, 0x20000000, 0xe8);
+ break;
+ case 3:
+ *(uint32_t*)0x20000240 = htobe32(0xe0000002);
+ *(uint8_t*)0x20000244 = 0xac;
+ *(uint8_t*)0x20000245 = 0x14;
+ *(uint8_t*)0x20000246 = 0x14;
+ *(uint8_t*)0x20000247 = 0xaa;
+ *(uint32_t*)0x20000248 = 1;
+ *(uint32_t*)0x2000024c = 2;
+ *(uint32_t*)0x20000250 = htobe32(0);
+ *(uint32_t*)0x20000254 = htobe32(0xe0000001);
+ syscall(__NR_setsockopt, r[0], 0, 0x29, 0x20000240, 0x18);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+ setup_leak();
+ do_sandbox_none();
+ return 0;
+}
diff --git a/syzkaller-repros/linux/fa9f4a0c5b1dc84273298312286f4c7ad1721698.c b/syzkaller-repros/linux/fa9f4a0c5b1dc84273298312286f4c7ad1721698.c
new file mode 100644
index 0000000..ca04621
--- /dev/null
+++ b/syzkaller-repros/linux/fa9f4a0c5b1dc84273298312286f4c7ad1721698.c
@@ -0,0 +1,91 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x200031c0 = 0;
+ *(uint32_t*)0x200031c8 = 0;
+ *(uint64_t*)0x200031d0 = 0x20003180;
+ *(uint64_t*)0x20003180 = 0x20003000;
+ *(uint32_t*)0x20003000 = 0x38;
+ *(uint16_t*)0x20003004 = 0x1403;
+ *(uint16_t*)0x20003006 = 1;
+ *(uint32_t*)0x20003008 = 0;
+ *(uint32_t*)0x2000300c = 0;
+ *(uint16_t*)0x20003010 = 9;
+ *(uint16_t*)0x20003012 = 2;
+ memcpy((void*)0x20003014, "syz1\000", 5);
+ *(uint16_t*)0x2000301c = 8;
+ *(uint16_t*)0x2000301e = 0x41;
+ memcpy((void*)0x20003020, "siw\000", 4);
+ *(uint16_t*)0x20003024 = 0x14;
+ *(uint16_t*)0x20003026 = 0x33;
+ memcpy((void*)0x20003028,
+ "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+ *(uint64_t*)0x20003188 = 0x38;
+ *(uint64_t*)0x200031d8 = 1;
+ *(uint64_t*)0x200031e0 = 0;
+ *(uint64_t*)0x200031e8 = 0;
+ *(uint32_t*)0x200031f0 = 0;
+ syscall(__NR_sendmsg, r[0], 0x200031c0ul, 0ul);
+ *(uint64_t*)0x20000500 = 0;
+ *(uint32_t*)0x20000508 = 0;
+ *(uint64_t*)0x20000510 = 0x200004c0;
+ *(uint64_t*)0x200004c0 = 0x20000000;
+ memcpy((void*)0x20000000,
+ "\x30\x00\x00\x00\x02\x07\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"
+ "\x00\x00\x00\x00\x00\x00\x00\x18\x00\x01",
+ 27);
+ *(uint64_t*)0x200004c8 = 1;
+ *(uint64_t*)0x20000518 = 1;
+ *(uint64_t*)0x20000520 = 0;
+ *(uint64_t*)0x20000528 = 0;
+ *(uint32_t*)0x20000530 = 0;
+ syscall(__NR_sendmsg, -1, 0x20000500ul, 0ul);
+ *(uint64_t*)0x20000200 = 0;
+ *(uint32_t*)0x20000208 = 0;
+ *(uint64_t*)0x20000210 = 0x200001c0;
+ *(uint64_t*)0x200001c0 = 0x20000000;
+ memcpy((void*)0x20000000, "\x28\x00\x00\x00\x4a\x00\x01", 7);
+ *(uint64_t*)0x200001c8 = 1;
+ *(uint64_t*)0x20000218 = 1;
+ *(uint64_t*)0x20000220 = 0;
+ *(uint64_t*)0x20000228 = 0;
+ *(uint32_t*)0x20000230 = 0;
+ syscall(__NR_sendmsg, -1, 0x20000200ul, 0ul);
+ *(uint64_t*)0x20001f80 = 0;
+ *(uint32_t*)0x20001f88 = 0;
+ *(uint64_t*)0x20001f90 = 0x20001f40;
+ *(uint64_t*)0x20001f40 = 0x20000000;
+ memcpy((void*)0x20000000, "\x14\x00\x00\x00\x04\x14", 6);
+ *(uint64_t*)0x20001f48 = 1;
+ *(uint64_t*)0x20001f98 = 1;
+ *(uint64_t*)0x20001fa0 = 0;
+ *(uint64_t*)0x20001fa8 = 0;
+ *(uint32_t*)0x20001fb0 = 0;
+ syscall(__NR_sendmsg, -1, 0x20001f80ul, 0ul);
+ res = syscall(__NR_socket, 0x10ul, 2ul, 0x14);
+ if (res != -1)
+ r[1] = res;
+ memcpy((void*)0x20000000, "E", 1);
+ syscall(__NR_sendto, r[1], 0x20000000ul, 0x10a73ul, 0x8c0ul, 0ul,
+ 0x4b6ae4f95a5de35bul);
+ return 0;
+}
diff --git a/syzkaller-repros/linux/ff30bd33030b8fd539566a6faf8ece5650b1038e.c b/syzkaller-repros/linux/ff30bd33030b8fd539566a6faf8ece5650b1038e.c
new file mode 100644
index 0000000..a49bb1e
--- /dev/null
+++ b/syzkaller-repros/linux/ff30bd33030b8fd539566a6faf8ece5650b1038e.c
@@ -0,0 +1,1618 @@
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+struct nlmsg {
+ char* pos;
+ int nesting;
+ struct nlattr* nested[8];
+ char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
+ const void* data, int size)
+{
+ memset(nlmsg, 0, sizeof(*nlmsg));
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_type = typ;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ memcpy(hdr + 1, data, size);
+ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
+}
+
+static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
+ int size)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_len = sizeof(*attr) + size;
+ attr->nla_type = typ;
+ memcpy(attr + 1, data, size);
+ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+ struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+ attr->nla_type = typ;
+ nlmsg->pos += sizeof(*attr);
+ nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+ attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+ int* reply_len)
+{
+ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+ exit(1);
+ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (n != hdr->nlmsg_len)
+ exit(1);
+ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+ if (hdr->nlmsg_type == NLMSG_DONE) {
+ *reply_len = 0;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr))
+ exit(1);
+ if (reply_len && hdr->nlmsg_type == reply_type) {
+ *reply_len = n;
+ return 0;
+ }
+ if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+ exit(1);
+ if (hdr->nlmsg_type != NLMSG_ERROR)
+ exit(1);
+ return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+ return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+ unsigned int total_len)
+{
+ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+ if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+ return -1;
+ return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+ const char* name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+ sizeof(hdr));
+ if (name)
+ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+ netlink_nest(nlmsg, IFLA_LINKINFO);
+ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* peer)
+{
+ netlink_add_device_impl(nlmsg, "veth", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_nest(nlmsg, VETH_INFO_PEER);
+ nlmsg->pos += sizeof(struct ifinfomsg);
+ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* slave1, const char* slave2)
+{
+ netlink_add_device_impl(nlmsg, "hsr", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ int ifindex1 = if_nametoindex(slave1);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+ int ifindex2 = if_nametoindex(slave2);
+ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
+ const char* name, const char* link)
+{
+ netlink_add_device_impl(nlmsg, type, name);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t id, uint16_t proto)
+{
+ netlink_add_device_impl(nlmsg, "vlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link)
+{
+ netlink_add_device_impl(nlmsg, "macvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ uint32_t mode = MACVLAN_MODE_BRIDGE;
+ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+ uint32_t vni, struct in_addr* addr4,
+ struct in6_addr* addr6)
+{
+ netlink_add_device_impl(nlmsg, "geneve", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+ if (addr4)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+ if (addr6)
+ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+ const char* link, uint16_t mode, uint16_t flags)
+{
+ netlink_add_device_impl(nlmsg, "ipvlan", name);
+ netlink_nest(nlmsg, IFLA_INFO_DATA);
+ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+ netlink_done(nlmsg);
+ netlink_done(nlmsg);
+ int ifindex = if_nametoindex(link);
+ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static void netlink_device_change(struct nlmsg* nlmsg, int sock,
+ const char* name, bool up, const char* master,
+ const void* mac, int macsize,
+ const char* new_name)
+{
+ struct ifinfomsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ if (up)
+ hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+ hdr.ifi_index = if_nametoindex(name);
+ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+ if (new_name)
+ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
+ if (master) {
+ int ifindex = if_nametoindex(master);
+ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
+ }
+ if (macsize)
+ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
+ int err = netlink_send(nlmsg, sock);
+ (void)err;
+}
+
+static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
+ const void* addr, int addrsize)
+{
+ struct ifaddrmsg hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
+ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
+ hdr.ifa_scope = RT_SCOPE_UNIVERSE;
+ hdr.ifa_index = if_nametoindex(dev);
+ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
+ sizeof(hdr));
+ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
+ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
+ return netlink_send(nlmsg, sock);
+}
+
+static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in_addr in_addr;
+ inet_pton(AF_INET, addr, &in_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
+ (void)err;
+}
+
+static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
+ const char* addr)
+{
+ struct in6_addr in6_addr;
+ inet_pton(AF_INET6, addr, &in6_addr);
+ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
+ (void)err;
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+ strlen(DEVLINK_FAMILY_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+ const char* netdev_prefix)
+{
+ struct genlmsghdr genlhdr;
+ int len, total_len, id, err, offset;
+ uint16_t netdev_index;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtsock == -1)
+ exit(1);
+ id = netlink_devlink_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = DEVLINK_CMD_PORT_GET;
+ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+ err = netlink_send_ext(&nlmsg, sock, id, &total_len);
+ if (err) {
+ goto error;
+ }
+ offset = 0;
+ netdev_index = 0;
+ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg.buf + offset + len;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+ char* port_name;
+ char netdev_name[IFNAMSIZ];
+ port_name = (char*)(attr + 1);
+ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+ netdev_index);
+ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+ netdev_name);
+ break;
+ }
+ }
+ offset += len;
+ netdev_index++;
+ }
+error:
+ close(rtsock);
+ close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+ char buf[16];
+ sprintf(buf, "%u %u", addr, port_count);
+ if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+ snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+ initialize_devlink_ports("netdevsim", buf, "netdevsim");
+ }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_id_get(struct nlmsg* nlmsg, int sock)
+{
+ struct genlmsghdr genlhdr;
+ struct nlattr* attr;
+ int err, n;
+ uint16_t id = 0;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = CTRL_CMD_GETFAMILY;
+ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, WG_GENL_NAME,
+ strlen(WG_GENL_NAME) + 1);
+ err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+ if (err) {
+ return -1;
+ }
+ attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+ NLMSG_ALIGN(sizeof(genlhdr)));
+ for (; (char*)attr < nlmsg->buf + n;
+ attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+ id = *(uint16_t*)(attr + 1);
+ break;
+ }
+ }
+ if (!id) {
+ return -1;
+ }
+ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+ return id;
+}
+
+static void netlink_wireguard_setup(void)
+{
+ const char ifname_a[] = "wg0";
+ const char ifname_b[] = "wg1";
+ const char ifname_c[] = "wg2";
+ const char private_a[] =
+ "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+ "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+ const char private_b[] =
+ "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+ "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+ const char private_c[] =
+ "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+ "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+ const char public_a[] =
+ "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+ "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+ const char public_b[] =
+ "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+ "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+ const char public_c[] =
+ "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+ "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+ const uint16_t listen_a = 20001;
+ const uint16_t listen_b = 20002;
+ const uint16_t listen_c = 20003;
+ const uint16_t af_inet = AF_INET;
+ const uint16_t af_inet6 = AF_INET6;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in endpoint_a_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_a),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+ const struct sockaddr_in endpoint_b_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_b),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ const struct sockaddr_in endpoint_c_v4 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(listen_c),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_a)};
+ endpoint_a_v6.sin6_addr = in6addr_loopback;
+ /* Unused, but useful in case we change this:
+ const struct sockaddr_in6 endpoint_b_v6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(listen_b)};
+ endpoint_b_v6.sin6_addr = in6addr_loopback; */
+ struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+ .sin6_port = htons(listen_c)};
+ endpoint_c_v6.sin6_addr = in6addr_loopback;
+ const struct in_addr first_half_v4 = {0};
+ const struct in_addr second_half_v4 = {htonl(128 << 24)};
+ const struct in6_addr first_half_v6 = {{{0}}};
+ const struct in6_addr second_half_v6 = {{{0x80}}};
+ const uint8_t half_cidr = 1;
+ const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+ struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+ int sock;
+ int id, err;
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock == -1)
+ exit(1);
+ id = netlink_wireguard_id_get(&nlmsg, sock);
+ if (id == -1)
+ goto error;
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[0], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+ sizeof(endpoint_c_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[1], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[2], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+ sizeof(endpoint_c_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[3], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+ sizeof(endpoint_a_v6));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[4], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+ sizeof(first_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+ sizeof(first_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+ sizeof(endpoint_b_v4));
+ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ &persistent_keepalives[5], 2);
+ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+ sizeof(second_half_v4));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+ sizeof(second_half_v6));
+ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ netlink_done(&nlmsg);
+ err = netlink_send(&nlmsg, sock);
+ if (err) {
+ }
+
+error:
+ close(sock);
+}
+static void initialize_netdevices(void)
+{
+ char netdevsim[16];
+ sprintf(netdevsim, "netdevsim%d", (int)procid);
+ struct {
+ const char* type;
+ const char* dev;
+ } devtypes[] = {
+ {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+ {"vcan", "vcan0"}, {"bond", "bond0"},
+ {"team", "team0"}, {"dummy", "dummy0"},
+ {"nlmon", "nlmon0"}, {"caif", "caif0"},
+ {"batadv", "batadv0"}, {"vxcan", "vxcan1"},
+ {"netdevsim", netdevsim}, {"veth", 0},
+ {"xfrm", "xfrm0"}, {"wireguard", "wg0"},
+ {"wireguard", "wg1"}, {"wireguard", "wg2"},
+ };
+ const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+ struct {
+ const char* name;
+ int macsize;
+ bool noipv6;
+ } devices[] = {
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN},
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
+ };
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+ sprintf(slave0, "%s_slave_0", devmasters[i]);
+ sprintf(veth0, "veth0_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave0, veth0);
+ sprintf(slave1, "%s_slave_1", devmasters[i]);
+ sprintf(veth1, "veth1_to_%s", devmasters[i]);
+ netlink_add_veth(&nlmsg, sock, slave1, veth1);
+ sprintf(master, "%s0", devmasters[i]);
+ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+ }
+ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+ "veth1_virt_wifi");
+ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+ IPVLAN_F_VEPA);
+ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+ char addr[32];
+ sprintf(addr, DEV_IPV4, 14 + 10);
+ struct in_addr geneve_addr4;
+ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+ exit(1);
+ struct in6_addr geneve_addr6;
+ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+ exit(1);
+ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+ netdevsim_add((int)procid, 4);
+ netlink_wireguard_setup();
+ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+ char addr[32];
+ sprintf(addr, DEV_IPV4, i + 10);
+ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+ if (!devices[i].noipv6) {
+ sprintf(addr, DEV_IPV6, i + 10);
+ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+ }
+ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+ devices[i].macsize, NULL);
+ }
+ close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1)
+ exit(1);
+ struct {
+ const char* type;
+ int macsize;
+ bool noipv6;
+ bool noup;
+ } devtypes[] = {
+ {"nr", 7, true},
+ {"rose", 5, true, true},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+ char dev[32], addr[32];
+ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+ netlink_add_addr4(&nlmsg, sock, dev, addr);
+ if (!devtypes[i].noipv6) {
+ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+ netlink_add_addr6(&nlmsg, sock, dev, addr);
+ }
+ int macsize = devtypes[i].macsize;
+ uint64_t macaddr = 0xbbbbbb +
+ ((unsigned long long)i << (8 * (macsize - 2))) +
+ (procid << (8 * (macsize - 1)));
+ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+ macsize, NULL);
+ }
+ close(sock);
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+ uint64_t pcnt, bcnt;
+};
+
+struct ipt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct ipt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct ipt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[5];
+ unsigned int underflow[5];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct ipt_table_desc {
+ const char* name;
+ struct ipt_getinfo info;
+ struct ipt_replace replace;
+};
+
+static struct ipt_table_desc ipv4_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+static struct ipt_table_desc ipv6_tables[] = {
+ {.name = "filter"}, {.name = "nat"}, {.name = "mangle"},
+ {.name = "raw"}, {.name = "security"},
+};
+
+#define IPT_BASE_CTL 64
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+
+struct arpt_getinfo {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_entries;
+ unsigned int size;
+};
+
+struct arpt_get_entries {
+ char name[32];
+ unsigned int size;
+ void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+struct arpt_replace {
+ char name[32];
+ unsigned int valid_hooks;
+ unsigned int num_entries;
+ unsigned int size;
+ unsigned int hook_entry[3];
+ unsigned int underflow[3];
+ unsigned int num_counters;
+ struct xt_counters* counters;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+struct arpt_table_desc {
+ const char* name;
+ struct arpt_getinfo info;
+ struct arpt_replace replace;
+};
+
+static struct arpt_table_desc arpt_tables[] = {
+ {.name = "filter"},
+};
+
+#define ARPT_BASE_CTL 96
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+
+static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct ipt_get_entries entries;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
+ int family, int level)
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct ipt_get_entries entries;
+ struct ipt_getinfo info;
+ socklen_t optlen;
+ int fd, i;
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < num_tables; i++) {
+ struct ipt_table_desc* table = &tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+ struct arpt_get_entries entries;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ strcpy(table->info.name, table->name);
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->info.size > sizeof(table->replace.entrytable))
+ exit(1);
+ if (table->info.num_entries > XT_MAX_ENTRIES)
+ exit(1);
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ table->replace.valid_hooks = table->info.valid_hooks;
+ table->replace.num_entries = table->info.num_entries;
+ table->replace.size = table->info.size;
+ memcpy(table->replace.hook_entry, table->info.hook_entry,
+ sizeof(table->replace.hook_entry));
+ memcpy(table->replace.underflow, table->info.underflow,
+ sizeof(table->replace.underflow));
+ memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
+ }
+ close(fd);
+}
+
+static void reset_arptables()
+{
+ struct xt_counters counters[XT_MAX_ENTRIES];
+ struct arpt_get_entries entries;
+ struct arpt_getinfo info;
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
+ struct arpt_table_desc* table = &arpt_tables[i];
+ if (table->info.valid_hooks == 0)
+ continue;
+ memset(&info, 0, sizeof(info));
+ strcpy(info.name, table->name);
+ optlen = sizeof(info);
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+ exit(1);
+ if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+ memset(&entries, 0, sizeof(entries));
+ strcpy(entries.name, table->name);
+ entries.size = table->info.size;
+ optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
+ if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
+ exit(1);
+ if (memcmp(table->replace.entrytable, entries.entrytable,
+ table->info.size) == 0)
+ continue;
+ } else {
+ }
+ table->replace.num_counters = info.num_entries;
+ table->replace.counters = counters;
+ optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
+ table->replace.size;
+ if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+#define NF_BR_NUMHOOKS 6
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN 32
+#define EBT_BASE_CTL 128
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ unsigned int nentries;
+ unsigned int entries_size;
+ struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
+ unsigned int num_counters;
+ struct ebt_counter* counters;
+ char* entries;
+};
+
+struct ebt_entries {
+ unsigned int distinguisher;
+ char name[EBT_CHAIN_MAXNAMELEN];
+ unsigned int counter_offset;
+ int policy;
+ unsigned int nentries;
+ char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
+};
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
+ &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ exit(1);
+ }
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ exit(1);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
+ &optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1) {
+ switch (errno) {
+ case EAFNOSUPPORT:
+ case ENOPROTOOPT:
+ return;
+ }
+ exit(1);
+ }
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ exit(1);
+ replace.num_counters = 0;
+ table->replace.entries = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ exit(1);
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] =
+ (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ exit(1);
+ }
+ close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+ checkpoint_ebtables();
+ checkpoint_arptables();
+ checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void reset_net_namespace(void)
+{
+ reset_ebtables();
+ reset_arptables();
+ reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
+ AF_INET, SOL_IP);
+ reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
+ AF_INET6, SOL_IPV6);
+}
+
+static void setup_common()
+{
+ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+ }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ setsid();
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+ setrlimit(RLIMIT_AS, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+ setrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
+ rlim.rlim_cur = rlim.rlim_max = 256;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ if (unshare(CLONE_NEWNS)) {
+ }
+ if (unshare(CLONE_NEWIPC)) {
+ }
+ if (unshare(0x02000000)) {
+ }
+ if (unshare(CLONE_NEWUTS)) {
+ }
+ if (unshare(CLONE_SYSVSEM)) {
+ }
+ typedef struct {
+ const char* name;
+ const char* value;
+ } sysctl_t;
+ static const sysctl_t sysctls[] = {
+ {"/proc/sys/kernel/shmmax", "16777216"},
+ {"/proc/sys/kernel/shmall", "536870912"},
+ {"/proc/sys/kernel/shmmni", "1024"},
+ {"/proc/sys/kernel/msgmax", "8192"},
+ {"/proc/sys/kernel/msgmni", "1024"},
+ {"/proc/sys/kernel/msgmnb", "1024"},
+ {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+ };
+ unsigned i;
+ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+ write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+ if (pid < 0)
+ exit(1);
+ int status = 0;
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+ struct __user_cap_header_struct cap_hdr = {};
+ struct __user_cap_data_struct cap_data[2] = {};
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = getpid();
+ if (syscall(SYS_capget, &cap_hdr, &cap_data))
+ exit(1);
+ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+ cap_data[0].effective &= ~drop;
+ cap_data[0].permitted &= ~drop;
+ cap_data[0].inheritable &= ~drop;
+ if (syscall(SYS_capset, &cap_hdr, &cap_data))
+ exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+ int pid = fork();
+ if (pid != 0)
+ return wait_for_loop(pid);
+ setup_common();
+ sandbox_common();
+ drop_caps();
+ initialize_netdevices_init();
+ if (unshare(CLONE_NEWNET)) {
+ }
+ initialize_netdevices();
+ loop();
+ exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ int i;
+ for (i = 0; i < 100; i++) {
+ if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+ return;
+ usleep(1000);
+ }
+ DIR* dir = opendir("/sys/fs/fuse/connections");
+ if (dir) {
+ for (;;) {
+ struct dirent* ent = readdir(dir);
+ if (!ent)
+ break;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ char abort[300];
+ snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
+ ent->d_name);
+ int fd = open(abort, O_WRONLY);
+ if (fd == -1) {
+ continue;
+ }
+ if (write(fd, abort, 1) < 0) {
+ }
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ }
+ while (waitpid(-1, status, __WALL) != pid) {
+ }
+}
+
+static void setup_loop()
+{
+ checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+ reset_net_namespace();
+}
+
+static void setup_test()
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ setpgrp();
+ write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+ int fd;
+ for (fd = 3; fd < MAX_FDS; fd++)
+ close(fd);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+ setup_loop();
+ int iter;
+ for (iter = 0;; iter++) {
+ reset_loop();
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ setup_test();
+ execute_one();
+ close_fds();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ sleep_ms(1);
+ if (current_time_ms() - start < 5 * 1000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+ intptr_t res = 0;
+ res = syscall(__NR_socket, 0x10ul, 3ul, 9ul);
+ if (res != -1)
+ r[0] = res;
+ *(uint64_t*)0x200006c0 = 0;
+ *(uint32_t*)0x200006c8 = 0;
+ *(uint64_t*)0x200006d0 = 0x20000040;
+ *(uint64_t*)0x20000040 = 0x20000000;
+ *(uint32_t*)0x20000000 = 0x34;
+ *(uint16_t*)0x20000004 = 0x3e9;
+ *(uint16_t*)0x20000006 = 0x400;
+ *(uint32_t*)0x20000008 = 0;
+ *(uint32_t*)0x2000000c = 0x25dfdc01;
+ *(uint32_t*)0x20000010 = 0x3f;
+ *(uint32_t*)0x20000014 = 1;
+ *(uint32_t*)0x20000018 = 2;
+ *(uint32_t*)0x2000001c = 0;
+ *(uint32_t*)0x20000020 = -1;
+ *(uint32_t*)0x20000024 = 2;
+ *(uint32_t*)0x20000028 = 4;
+ *(uint32_t*)0x2000002c = 0;
+ *(uint32_t*)0x20000030 = 0;
+ *(uint64_t*)0x20000048 = 0x34;
+ *(uint64_t*)0x200006d8 = 1;
+ *(uint64_t*)0x200006e0 = 0;
+ *(uint64_t*)0x200006e8 = 0;
+ *(uint32_t*)0x200006f0 = 0x40040c1;
+ syscall(__NR_sendmsg, r[0], 0x200006c0ul, 0ul);
+}
+int main(void)
+{
+ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+ do_sandbox_none();
+ return 0;
+}