1 /**
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #define _GNU_SOURCE
17 #define ARRAY_SIZE(__a) (sizeof(__a) / sizeof((__a)[0]))
18 #include <errno.h>
19 #include <linux/filter.h>
20 #include <linux/netlink.h>
21 #include <stdlib.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 
27 static struct sock_filter nlattr[] = {
28   { 0000, 0, 0, 0x87654321 },
29   { 0x01, 0, 0, 0x0000002a },
30   { 0x20, 0, 0, 0xfffff00c },
31   { 0x16, 0, 0, 0000000000 },
32 };
33 
34 static struct sock_fprog bpf_nlattr = {
35   .len = ARRAY_SIZE(nlattr),
36   .filter = nlattr,
37 };
38 
39 static struct sock_filter nlattr_nest[] = {
40   { 0000, 0, 0, 0x87654321 },
41   { 0x01, 0, 0, 0x0000002a },
42   { 0x20, 0, 0, 0xfffff010 },
43   { 0x16, 0, 0, 0000000000 },
44 };
45 
46 static struct sock_fprog bpf_nlattr_nest = {
47   .len = ARRAY_SIZE(nlattr_nest),
48   .filter = nlattr_nest,
49 };
50 
51 static struct sock_filter nest_rem[] = {
52   { 0000, 0, 0, 0000000000 },
53   { 0x01, 0, 0, 0x0000002a },
54   { 0x20, 0, 0, 0xfffff010 },
55   { 0x16, 0, 0, 0000000000 },
56 };
57 
58 static struct sock_fprog bpf_nest_rem = {
59   .len = ARRAY_SIZE(nest_rem),
60   .filter = nest_rem,
61 };
62 
send_receive_packet(int s[2],const void * pkt,int len)63 static int send_receive_packet(int s[2], const void* pkt, int len)
64 {
65   char tmp[1024];
66   ssize_t ret;
67 
68   ret = send(s[1], pkt, len, 0);
69   if (ret != len) {
70     return -1;
71   }
72 
73   ret = recv(s[0], tmp, len, MSG_DONTWAIT);
74   if (ret < 0 && errno == EAGAIN)
75     return 0;
76 
77   return 1;
78 }
79 
main()80 int main()
81 {
82   struct nlattr chkrem[2] = {
83     [0] = {
84         .nla_len = 0xfff0,
85         .nla_type = 0,
86     },
87     [1] = {
88         .nla_len = sizeof(struct nlattr),
89         .nla_type = 42,
90     },
91   };
92   __u16 chksz = 0xfefe;
93   int s[2], ret;
94 
95   ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, s);
96   if (ret) {
97     return -1;
98   }
99 
100   ret = setsockopt(s[0], SOL_SOCKET, SO_ATTACH_FILTER,
101       &bpf_nlattr, sizeof(bpf_nlattr));
102   if (ret < 0) {
103     return -1;
104   }
105 
106   ret = send_receive_packet(s, &chksz, sizeof(chksz));
107   if (ret) {
108     ret = 113;
109     goto out;
110   }
111 
112   ret = setsockopt(s[0], SOL_SOCKET, SO_ATTACH_FILTER,
113       &bpf_nlattr_nest, sizeof(bpf_nlattr_nest));
114   if (ret < 0) {
115     return -1;
116   }
117 
118   ret = send_receive_packet(s, &chksz, sizeof(chksz));
119   if (ret) {
120     ret = 113;
121     goto out;
122   }
123 
124   ret = setsockopt(s[0], SOL_SOCKET, SO_ATTACH_FILTER,
125       &bpf_nest_rem, sizeof(bpf_nest_rem));
126   if (ret < 0) {
127     return -1;
128   }
129 
130   ret = send_receive_packet(s, chkrem, sizeof(chkrem));
131   if(ret){
132     ret = 113;
133   }
134 
135 out:
136   return ret;
137 }
138