155682Smarkm/*- 2233294Sstas * SPDX-License-Identifier: BSD-2-Clause 3233294Sstas * 4233294Sstas * Copyright (c) 2021-2023, Juniper Networks, Inc. 555682Smarkm * All rights reserved. 6233294Sstas * 7233294Sstas * Redistribution and use in source and binary forms, with or without 8233294Sstas * modification, are permitted provided that the following conditions 955682Smarkm * are met: 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 13233294Sstas * notice, this list of conditions and the following disclaimer in the 14233294Sstas * documentation and/or other materials provided with the distribution. 15233294Sstas * 1655682Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17233294Sstas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18233294Sstas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19233294Sstas * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2055682Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21233294Sstas * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22233294Sstas * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23233294Sstas * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24233294Sstas * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26233294Sstas * SUCH DAMAGE. 27233294Sstas * 28233294Sstas */ 29233294Sstas 30233294Sstas#include <sys/types.h> 31233294Sstas#include <sys/errno.h> 3255682Smarkm#include <sys/mac.h> 3355682Smarkm 3455682Smarkm#include <unistd.h> 3555682Smarkm#include <string.h> 3690926Snectar 3755682Smarkm#include <security/mac_veriexec/mac_veriexec.h> 3890926Snectar 3990926Snectar/** 4090926Snectar * @brief get veriexec params for a process 4190926Snectar * 4290926Snectar * @return 4390926Snectar * @li 0 if successful 4455682Smarkm */ 4555682Smarkmint 4655682Smarkmveriexec_get_pid_params(pid_t pid, 47178825Sdfr struct mac_veriexec_syscall_params *params) 48178825Sdfr{ 4955682Smarkm struct mac_veriexec_syscall_params_args args; 5055682Smarkm 5155682Smarkm if (params == NULL) 5255682Smarkm return EINVAL; 5355682Smarkm 5455682Smarkm args.u.pid = pid; 5555682Smarkm args.params = params; 5655682Smarkm return mac_syscall(MAC_VERIEXEC_NAME, 5755682Smarkm MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL, &args); 58178825Sdfr} 5955682Smarkm 6055682Smarkm/** 6155682Smarkm * @brief get veriexec params for a path 6255682Smarkm * 6355682Smarkm * @return 6455682Smarkm * @li 0 if successful 6555682Smarkm */ 66178825Sdfrint 6755682Smarkmveriexec_get_path_params(const char *file, 68178825Sdfr struct mac_veriexec_syscall_params *params) 69233294Sstas{ 70233294Sstas struct mac_veriexec_syscall_params_args args; 7155682Smarkm 72178825Sdfr if (file == NULL || params == NULL) 7355682Smarkm return EINVAL; 7455682Smarkm 7555682Smarkm args.u.filename = file; 7655682Smarkm args.params = params; 7755682Smarkm return mac_syscall(MAC_VERIEXEC_NAME, 7855682Smarkm MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL, &args); 79178825Sdfr} 8055682Smarkm 81178825Sdfr/** 82233294Sstas * @brief return label associated with a path 83233294Sstas * 8455682Smarkm * @param[in] file 85178825Sdfr * pathname of file to lookup. 8655682Smarkm * 8755682Smarkm * @prarm[in] buf 8855682Smarkm * if not NULL and big enough copy label to buf. 8955682Smarkm * otherwise return a copy of label. 9055682Smarkm * 9155682Smarkm * @param[in] bufsz 92178825Sdfr * size of buf, must be greater than found label length. 9355682Smarkm * 94178825Sdfr * @return 9555682Smarkm * @li NULL if no label 9655682Smarkm * @li pointer to label 9755682Smarkm */ 9855682Smarkmchar * 99178825Sdfrveriexec_get_path_label(const char *file, char *buf, size_t bufsz) 100178825Sdfr{ 101233294Sstas struct mac_veriexec_syscall_params params; 10255682Smarkm char *cp; 103178825Sdfr 104178825Sdfr cp = NULL; 105178825Sdfr if (veriexec_get_path_params(file, ¶ms) == 0) { 106178825Sdfr /* Does label contain a label */ 107178825Sdfr if (params.labellen > 0) { 108233294Sstas if (buf != NULL && bufsz > params.labellen) { 109233294Sstas strlcpy(buf, params.label, bufsz); 110178825Sdfr cp = buf; 111178825Sdfr } else 112178825Sdfr cp = strdup(params.label); 113233294Sstas } 11455682Smarkm } 115178825Sdfr return cp; 11655682Smarkm} 11755682Smarkm 11855682Smarkm/** 11955682Smarkm * @brief return label of a process 12055682Smarkm * 121178825Sdfr * 122178825Sdfr * @param[in] pid 12355682Smarkm * process id of interest. 124178825Sdfr * 125178825Sdfr * @prarm[in] buf 12672445Sassar * if not NULL and big enough copy label to buf. 12772445Sassar * otherwise return a copy of label. 12872445Sassar * 129178825Sdfr * @param[in] bufsz 130178825Sdfr * size of buf, must be greater than found label length. 131178825Sdfr * 13272445Sassar * @return 133233294Sstas * @li NULL if no label 13472445Sassar * @li pointer to label 13572445Sassar */ 136178825Sdfrchar * 13772445Sassarveriexec_get_pid_label(pid_t pid, char *buf, size_t bufsz) 13855682Smarkm{ 13972445Sassar struct mac_veriexec_syscall_params params; 14055682Smarkm char *cp; 14155682Smarkm 14255682Smarkm cp = NULL; 14355682Smarkm if (veriexec_get_pid_params(pid, ¶ms) == 0) { 144178825Sdfr /* Does label contain a label */ 14555682Smarkm if (params.labellen > 0) { 14655682Smarkm if (buf != NULL && bufsz > params.labellen) { 14755682Smarkm strlcpy(buf, params.label, bufsz); 14855682Smarkm cp = buf; 14955682Smarkm } else 15055682Smarkm cp = strdup(params.label); 151178825Sdfr } 15255682Smarkm } 15355682Smarkm return cp; 15455682Smarkm} 15555682Smarkm 15655682Smarkm/* 15755682Smarkm * we match 15855682Smarkm * ^want$ 15955682Smarkm * ^want, 16055682Smarkm * ,want, 16155682Smarkm * ,want$ 162178825Sdfr * 16355682Smarkm * and if want ends with / then we match that prefix too. 16455682Smarkm */ 16555682Smarkmstatic int 16655682Smarkmcheck_label_want(const char *label, size_t labellen, 16755682Smarkm const char *want, size_t wantlen) 16855682Smarkm{ 169233294Sstas char *cp; 170178825Sdfr 171178825Sdfr /* Does label contain [,]<want>[,] ? */ 17255682Smarkm if (labellen > 0 && wantlen > 0 && 17355682Smarkm (cp = strstr(label, want)) != NULL) { 17455682Smarkm if (cp == label || cp[-1] == ',') { 17555682Smarkm if (cp[wantlen] == '\0' || cp[wantlen] == ',' || 17655682Smarkm (cp[wantlen-1] == '/' && want[wantlen-1] == '/')) 17755682Smarkm return 1; /* yes */ 178178825Sdfr } 17955682Smarkm } 18055682Smarkm return 0; /* no */ 18155682Smarkm} 18255682Smarkm 18355682Smarkm/** 184178825Sdfr * @brief check if a process has label that contains what we want 18555682Smarkm * 18655682Smarkm * @param[in] pid 187178825Sdfr * process id of interest. 188178825Sdfr * 189178825Sdfr * @param[in] want 190178825Sdfr * the label we are looking for 191233294Sstas * if want ends with ``/`` it is assumed a prefix 192233294Sstas * otherwise we expect it to be followed by ``,`` or end of string. 193178825Sdfr * 194178825Sdfr * @return 195178825Sdfr * @li 0 if no 196233294Sstas * @li 1 if yes 19755682Smarkm */ 198178825Sdfrint 199233294Sstasveriexec_check_pid_label(pid_t pid, const char *want) 20055682Smarkm{ 20155682Smarkm struct mac_veriexec_syscall_params params; 20255682Smarkm size_t n; 20355682Smarkm 20455682Smarkm if (want != NULL && 205233294Sstas (n = strlen(want)) > 0 && 20655682Smarkm veriexec_get_pid_params(pid, ¶ms) == 0) { 20755682Smarkm return check_label_want(params.label, params.labellen, 208178825Sdfr want, n); 20955682Smarkm } 21055682Smarkm return 0; /* no */ 21155682Smarkm} 21255682Smarkm 21355682Smarkm/** 21455682Smarkm * @brief check if a path has label that contains what we want 21555682Smarkm * 216178825Sdfr * @param[in] path 21755682Smarkm * pathname of interest. 21855682Smarkm * 219178825Sdfr * @param[in] want 220178825Sdfr * the label we are looking for 221178825Sdfr * if want ends with ``/`` it is assumed a prefix 222178825Sdfr * otherwise we expect it to be followed by ``,`` or end of string. 223233294Sstas * 224233294Sstas * @return 225178825Sdfr * @li 0 if no 226178825Sdfr * @li 1 if yes 227178825Sdfr */ 228233294Sstasint 22955682Smarkmveriexec_check_path_label(const char *file, const char *want) 230178825Sdfr{ 23155682Smarkm struct mac_veriexec_syscall_params params; 23255682Smarkm size_t n; 23355682Smarkm 23455682Smarkm if (want != NULL && file != NULL && 23555682Smarkm (n = strlen(want)) > 0 && 23655682Smarkm veriexec_get_path_params(file, ¶ms) == 0) { 237178825Sdfr return check_label_want(params.label, params.labellen, 23855682Smarkm want, n); 23955682Smarkm } 24055682Smarkm return 0; /* no */ 24155682Smarkm} 242178825Sdfr 24355682Smarkm#ifdef UNIT_TEST 24455682Smarkm#include <stdlib.h> 245178825Sdfr#include <stdio.h> 246178825Sdfr#include <err.h> 247178825Sdfr 248178825Sdfrstatic char * 249233294Sstashash2hex(char *type, unsigned char *digest) 250233294Sstas{ 251178825Sdfr static char buf[2*MAXFINGERPRINTLEN+1]; 252178825Sdfr size_t n; 25355682Smarkm int i; 25455682Smarkm 25555682Smarkm if (strcmp(type, "SHA1") == 0) { 25655682Smarkm n = 20; 25755682Smarkm } else if (strcmp(type, "SHA256") == 0) { 25855682Smarkm n = 32; 25955682Smarkm } else if (strcmp(type, "SHA384") == 0) { 26055682Smarkm n = 48; 26155682Smarkm } 26255682Smarkm for (i = 0; i < n; i++) { 26355682Smarkm sprintf(&buf[2*i], "%02x", (unsigned)digest[i]); 264178825Sdfr } 26590926Snectar return buf; 266233294Sstas} 26755682Smarkm 26890926Snectarint 269178825Sdfrmain(int argc, char *argv[]) 27055682Smarkm{ 27155682Smarkm struct mac_veriexec_syscall_params params; 272178825Sdfr pid_t pid; 273178825Sdfr char buf[BUFSIZ]; 274178825Sdfr const char *cp; 27590926Snectar char *want = NULL; 276233294Sstas int lflag = 0; 277178825Sdfr int pflag = 0; 27890926Snectar int error; 27990926Snectar int c; 28055682Smarkm 28155682Smarkm while ((c = getopt(argc, argv, "lpw:")) != -1) { 28255682Smarkm switch (c) { 28355682Smarkm case 'l': 28490926Snectar lflag = 1; 285233294Sstas break; 28655682Smarkm case 'p': 28790926Snectar pflag = 1; 288178825Sdfr break; 289178825Sdfr case 'w': 290233294Sstas want = optarg; 291233294Sstas break; 292233294Sstas default: 293178825Sdfr break; 294178825Sdfr } 29555682Smarkm } 29655682Smarkm for (; optind < argc; optind++) { 29755682Smarkm 29855682Smarkm if (pflag) { 299233294Sstas pid = atoi(argv[optind]); 30055682Smarkm if (lflag) { 30155682Smarkm cp = veriexec_get_pid_label(pid, buf, sizeof(buf)); 302178825Sdfr if (cp) 30390926Snectar printf("pid=%d label='%s'\n", pid, cp); 304233294Sstas continue; 30555682Smarkm } 30690926Snectar if (want) { 30755682Smarkm error = veriexec_check_pid_label(pid, want); 308178825Sdfr printf("pid=%d want='%s': %d\n", 309178825Sdfr pid, want, error); 310178825Sdfr continue; 31190926Snectar } 31290926Snectar error = veriexec_get_pid_params(pid, ¶ms); 313233294Sstas } else { 31490926Snectar if (lflag) { 31590926Snectar cp = veriexec_get_path_label(argv[optind], 316178825Sdfr buf, sizeof(buf)); 317178825Sdfr if (cp) 318233294Sstas printf("path='%s' label='%s'\n", 319178825Sdfr argv[optind], cp); 320178825Sdfr continue; 321233294Sstas } 322178825Sdfr if (want) { 323178825Sdfr error = veriexec_check_path_label(argv[optind], want); 324178825Sdfr printf("path='%s' want='%s': %d\n", 325178825Sdfr argv[optind], want, error); 326178825Sdfr continue; 327178825Sdfr } 328178825Sdfr error = veriexec_get_path_params(argv[optind], ¶ms); 329178825Sdfr } 330178825Sdfr if (error) { 331178825Sdfr err(2, "%s, error=%d", argv[optind], error); 332178825Sdfr } 33355682Smarkm 33455682Smarkm printf("arg=%s, type=%s, flags=%u, label='%s', fingerprint='%s'\n", 33555682Smarkm argv[optind], params.fp_type, (unsigned)params.flags, 33690926Snectar params.label, 337 hash2hex(params.fp_type, params.fingerprint)); 338 } 339 return 0; 340} 341#endif 342