]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libveriexec/veriexec_get.c
lib{c,lzma,z}: remove -DSYMBOL_VERSIONING from CFLAGS
[FreeBSD/FreeBSD.git] / lib / libveriexec / veriexec_get.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021-2023, Juniper Networks, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29
30 #include <sys/cdefs.h>
31 #include <sys/types.h>
32 #include <sys/errno.h>
33 #include <sys/mac.h>
34
35 #include <unistd.h>
36 #include <string.h>
37
38 #include <security/mac_veriexec/mac_veriexec.h>
39
40 /**
41  * @brief get veriexec params for a process
42  *
43  * @return
44  * @li 0 if successful
45  */
46 int
47 veriexec_get_pid_params(pid_t pid,
48     struct mac_veriexec_syscall_params *params)
49 {
50         struct mac_veriexec_syscall_params_args args;
51
52         if (params == NULL)
53                 return EINVAL;
54
55         args.u.pid = pid;
56         args.params = params;
57         return mac_syscall(MAC_VERIEXEC_NAME,
58             MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL, &args);
59 }
60
61 /**
62  * @brief get veriexec params for a path
63  *
64  * @return
65  * @li 0 if successful
66  */
67 int
68 veriexec_get_path_params(const char *file,
69     struct mac_veriexec_syscall_params *params)
70 {
71         struct mac_veriexec_syscall_params_args args;
72
73         if (file == NULL || params == NULL)
74                 return EINVAL;
75
76         args.u.filename = file;
77         args.params = params;
78         return mac_syscall(MAC_VERIEXEC_NAME,
79             MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL, &args);
80 }
81
82 /**
83  * @brief return label associated with a path
84  *
85  * @param[in] file
86  *      pathname of file to lookup.
87  *
88  * @prarm[in] buf
89  *      if not NULL and big enough copy label to buf.
90  *      otherwise return a copy of label.
91  *
92  * @param[in] bufsz
93  *      size of buf, must be greater than found label length.
94  *
95  * @return
96  * @li NULL if no label
97  * @li pointer to label
98  */
99 char *
100 veriexec_get_path_label(const char *file, char *buf, size_t bufsz)
101 {
102         struct mac_veriexec_syscall_params params;
103         char *cp;
104
105         cp = NULL;
106         if (veriexec_get_path_params(file, &params) == 0) {
107                 /* Does label contain a label */
108                 if (params.labellen > 0) {
109                         if (buf != NULL && bufsz > params.labellen) {
110                                 strlcpy(buf, params.label, bufsz);
111                                 cp = buf;
112                         } else
113                                 cp = strdup(params.label);
114                 }
115         }
116         return cp;
117 }
118
119 /**
120  * @brief return label of a process
121  *
122  *
123  * @param[in] pid
124  *      process id of interest.
125  *
126  * @prarm[in] buf
127  *      if not NULL and big enough copy label to buf.
128  *      otherwise return a copy of label.
129  *
130  * @param[in] bufsz
131  *      size of buf, must be greater than found label length.
132  *
133  * @return
134  * @li NULL if no label
135  * @li pointer to label
136  */
137 char *
138 veriexec_get_pid_label(pid_t pid, char *buf, size_t bufsz)
139 {
140         struct mac_veriexec_syscall_params params;
141         char *cp;
142
143         cp = NULL;
144         if (veriexec_get_pid_params(pid, &params) == 0) {
145                 /* Does label contain a label */
146                 if (params.labellen > 0) {
147                         if (buf != NULL && bufsz > params.labellen) {
148                                 strlcpy(buf, params.label, bufsz);
149                                 cp = buf;
150                         } else
151                                 cp = strdup(params.label);
152                 }
153         }
154         return cp;
155 }
156
157 /*
158  * we match
159  * ^want$
160  * ^want,
161  * ,want,
162  * ,want$
163  *
164  * and if want ends with / then we match that prefix too.
165  */
166 static int
167 check_label_want(const char *label, size_t labellen,
168     const char *want, size_t wantlen)
169 {
170         char *cp;
171
172         /* Does label contain [,]<want>[,] ? */
173         if (labellen > 0 && wantlen > 0 &&
174             (cp = strstr(label, want)) != NULL) {
175                 if (cp == label || cp[-1] == ',') {
176                         if (cp[wantlen] == '\0' || cp[wantlen] == ',' ||
177                             (cp[wantlen-1] == '/' && want[wantlen-1] == '/'))
178                                 return 1; /* yes */
179                 }
180         }
181         return 0;                       /* no */
182 }
183         
184 /**
185  * @brief check if a process has label that contains what we want
186  *
187  * @param[in] pid
188  *      process id of interest.
189  *
190  * @param[in] want
191  *      the label we are looking for
192  *      if want ends with ``/`` it is assumed a prefix
193  *      otherwise we expect it to be followed by ``,`` or end of string.
194  *
195  * @return
196  * @li 0 if no
197  * @li 1 if yes
198  */
199 int
200 veriexec_check_pid_label(pid_t pid, const char *want)
201 {
202         struct mac_veriexec_syscall_params params;
203         size_t n;
204
205         if (want != NULL &&
206             (n = strlen(want)) > 0 &&
207             veriexec_get_pid_params(pid, &params) == 0) {
208                 return check_label_want(params.label, params.labellen,
209                     want, n);
210         }
211         return 0;                       /* no */
212 }
213
214 /**
215  * @brief check if a path has label that contains what we want
216  *
217  * @param[in] path
218  *      pathname of interest.
219  *
220  * @param[in] want
221  *      the label we are looking for
222  *      if want ends with ``/`` it is assumed a prefix
223  *      otherwise we expect it to be followed by ``,`` or end of string.
224  *
225  * @return
226  * @li 0 if no
227  * @li 1 if yes
228  */
229 int
230 veriexec_check_path_label(const char *file, const char *want)
231 {
232         struct mac_veriexec_syscall_params params;
233         size_t n;
234
235         if (want != NULL && file != NULL &&
236             (n = strlen(want)) > 0 &&
237             veriexec_get_path_params(file, &params) == 0) {
238                 return check_label_want(params.label, params.labellen,
239                     want, n);
240         }
241         return 0;                       /* no */
242 }
243
244 #ifdef UNIT_TEST
245 #include <stdlib.h>
246 #include <stdio.h>
247 #include <err.h>
248
249 static char *
250 hash2hex(char *type, unsigned char *digest)
251 {
252         static char buf[2*MAXFINGERPRINTLEN+1];
253         size_t n;
254         int i;
255
256         if (strcmp(type, "SHA1") == 0) {
257                 n = 20;
258         } else if (strcmp(type, "SHA256") == 0) {
259                 n = 32;
260         } else if (strcmp(type, "SHA384") == 0) {
261                 n = 48;
262         }
263         for (i = 0; i < n; i++) {
264                 sprintf(&buf[2*i], "%02x", (unsigned)digest[i]);
265         }
266         return buf;
267 }
268
269 int
270 main(int argc, char *argv[])
271 {
272         struct mac_veriexec_syscall_params params;
273         pid_t pid;
274         char buf[BUFSIZ];
275         const char *cp;
276         char *want = NULL;
277         int lflag = 0;
278         int pflag = 0;
279         int error;
280         int c;
281
282         while ((c = getopt(argc, argv, "lpw:")) != -1) {
283                 switch (c) {
284                 case 'l':
285                         lflag = 1;
286                         break;
287                 case 'p':
288                         pflag = 1;
289                         break;
290                 case 'w':
291                         want = optarg;
292                         break;
293                 default:
294                         break;
295                 }
296         }
297         for (; optind < argc; optind++) {
298
299                 if (pflag) {
300                         pid = atoi(argv[optind]);
301                         if (lflag) {
302                                 cp = veriexec_get_pid_label(pid, buf, sizeof(buf));
303                                 if (cp)
304                                         printf("pid=%d label='%s'\n", pid, cp);
305                                 continue;
306                         }
307                         if (want) {
308                                 error = veriexec_check_pid_label(pid, want);
309                                 printf("pid=%d want='%s': %d\n",
310                                     pid, want, error);
311                                 continue;
312                         }
313                         error = veriexec_get_pid_params(pid, &params);
314                 } else {
315                         if (lflag) {
316                                 cp = veriexec_get_path_label(argv[optind],
317                                     buf, sizeof(buf));
318                                 if (cp)
319                                         printf("path='%s' label='%s'\n",
320                                             argv[optind], cp);
321                                 continue;
322                         }
323                         if (want) {
324                                 error = veriexec_check_path_label(argv[optind], want);
325                                 printf("path='%s' want='%s': %d\n",
326                                     argv[optind], want, error);
327                                 continue;
328                         }
329                         error = veriexec_get_path_params(argv[optind], &params);
330                 }
331                 if (error) {
332                         err(2, "%s, error=%d", argv[optind], error);
333                 }
334
335                 printf("arg=%s, type=%s, flags=%u, label='%s', fingerprint='%s'\n",
336                     argv[optind], params.fp_type, (unsigned)params.flags,
337                     params.label,
338                     hash2hex(params.fp_type, params.fingerprint));
339         }
340         return 0;
341 }
342 #endif