libexplain
1.4.D001
|
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 : */