libexplain  1.4.D001
libexplain/buffer/einval/ppp_filter.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2010, 2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU Lesser General Public License as
00007  * published by the Free Software Foundation; either version 3 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <libexplain/ac/linux/filter.h>
00020 #include <libexplain/ac/stdio.h>
00021 
00022 #include <libexplain/buffer/einval.h>
00023 #include <libexplain/buffer/gettext.h>
00024 
00025 #ifdef BPF_ALU
00026 
00027 static int
00028 instruction_ok(const struct sock_filter *ftest, unsigned pc, unsigned flen)
00029 {
00030     /* Linux: net/core/filter.c, sk_chk_filter */
00031     switch (ftest->code)
00032     {
00033     case BPF_ALU|BPF_ADD|BPF_K:
00034     case BPF_ALU|BPF_ADD|BPF_X:
00035     case BPF_ALU|BPF_SUB|BPF_K:
00036     case BPF_ALU|BPF_SUB|BPF_X:
00037     case BPF_ALU|BPF_MUL|BPF_K:
00038     case BPF_ALU|BPF_MUL|BPF_X:
00039     case BPF_ALU|BPF_DIV|BPF_X:
00040     case BPF_ALU|BPF_AND|BPF_K:
00041     case BPF_ALU|BPF_AND|BPF_X:
00042     case BPF_ALU|BPF_OR|BPF_K:
00043     case BPF_ALU|BPF_OR|BPF_X:
00044     case BPF_ALU|BPF_LSH|BPF_K:
00045     case BPF_ALU|BPF_LSH|BPF_X:
00046     case BPF_ALU|BPF_RSH|BPF_K:
00047     case BPF_ALU|BPF_RSH|BPF_X:
00048     case BPF_ALU|BPF_NEG:
00049     case BPF_LD|BPF_W|BPF_ABS:
00050     case BPF_LD|BPF_H|BPF_ABS:
00051     case BPF_LD|BPF_B|BPF_ABS:
00052     case BPF_LD|BPF_W|BPF_LEN:
00053     case BPF_LD|BPF_W|BPF_IND:
00054     case BPF_LD|BPF_H|BPF_IND:
00055     case BPF_LD|BPF_B|BPF_IND:
00056     case BPF_LD|BPF_IMM:
00057     case BPF_LDX|BPF_W|BPF_LEN:
00058     case BPF_LDX|BPF_B|BPF_MSH:
00059     case BPF_LDX|BPF_IMM:
00060     case BPF_MISC|BPF_TAX:
00061     case BPF_MISC|BPF_TXA:
00062     case BPF_RET|BPF_K:
00063     case BPF_RET|BPF_A:
00064         break;
00065 
00066     /* Some instructions need special checks */
00067 
00068     case BPF_ALU|BPF_DIV|BPF_K:
00069         /* check for division by zero */
00070         if (ftest->k == 0)
00071             return 0;
00072         break;
00073 
00074     case BPF_LD|BPF_MEM:
00075     case BPF_LDX|BPF_MEM:
00076     case BPF_ST:
00077     case BPF_STX:
00078         /* check for invalid memory addresses */
00079         if (ftest->k >= BPF_MEMWORDS)
00080             return 0;
00081         break;
00082 
00083     case BPF_JMP|BPF_JA:
00084         if (ftest->k >= (unsigned)(flen - pc - 1))
00085             return 0;
00086         break;
00087 
00088     case BPF_JMP|BPF_JEQ|BPF_K:
00089     case BPF_JMP|BPF_JEQ|BPF_X:
00090     case BPF_JMP|BPF_JGE|BPF_K:
00091     case BPF_JMP|BPF_JGE|BPF_X:
00092     case BPF_JMP|BPF_JGT|BPF_K:
00093     case BPF_JMP|BPF_JGT|BPF_X:
00094     case BPF_JMP|BPF_JSET|BPF_K:
00095     case BPF_JMP|BPF_JSET|BPF_X:
00096         /* for conditionals both must be safe */
00097         if (pc + ftest->jt + 1 >= flen || pc + ftest->jf + 1 >= flen)
00098             return 0;
00099         break;
00100 
00101     default:
00102         return 0;
00103     }
00104     return 1;
00105 }
00106 
00107 
00108 void
00109 explain_buffer_einval_sock_fprog(explain_string_buffer_t *sb,
00110     const struct sock_fprog *data)
00111 {
00112     unsigned        pc;
00113 
00114     /* Linux: net/core/filter.c, sk_chk_filter() */
00115     if (data->len == 0 || data->len > BPF_MAXINSNS)
00116         explain_buffer_einval_vague(sb, "data->len");
00117 
00118     for (pc = 0; pc < data->len; ++pc)
00119     {
00120         const struct sock_filter *ftest;
00121 
00122         ftest = &data->filter[pc];
00123         if (!instruction_ok(ftest, pc, data->len))
00124         {
00125             char buffer[30];
00126             snprintf(buffer, sizeof(buffer), "data->filter[%u]", pc);
00127             explain_buffer_einval_vague(sb, buffer);
00128             return;
00129         }
00130     }
00131     explain_buffer_einval_vague(sb, "data");
00132 }
00133 
00134 #else
00135 
00136 void
00137 explain_buffer_einval_sock_fprog(explain_string_buffer_t *sb,
00138     const struct sock_fprog *data)
00139 {
00140     (void)data;
00141     explain_buffer_einval_vague(sb, "data");
00142 }
00143 
00144 #endif
00145 
00146 
00147 /* vim: set ts=8 sw=4 et : */