| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * ebtables |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 8 | 9 | * |
|---|
| 9 | 10 | * This code is strongly inspired by the iptables code which is |
|---|
| 10 | 11 | * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is free software; you can redistribute it and/or |
|---|
| 13 | | - * modify it under the terms of the GNU General Public License |
|---|
| 14 | | - * as published by the Free Software Foundation; either version |
|---|
| 15 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 16 | 12 | */ |
|---|
| 17 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| 18 | 14 | #include <linux/kmod.h> |
|---|
| .. | .. |
|---|
| 381 | 377 | par->match = match; |
|---|
| 382 | 378 | par->matchinfo = m->data; |
|---|
| 383 | 379 | ret = xt_check_match(par, m->match_size, |
|---|
| 384 | | - e->ethproto, e->invflags & EBT_IPROTO); |
|---|
| 380 | + ntohs(e->ethproto), e->invflags & EBT_IPROTO); |
|---|
| 385 | 381 | if (ret < 0) { |
|---|
| 386 | 382 | module_put(match->me); |
|---|
| 387 | 383 | return ret; |
|---|
| .. | .. |
|---|
| 418 | 414 | par->target = watcher; |
|---|
| 419 | 415 | par->targinfo = w->data; |
|---|
| 420 | 416 | ret = xt_check_target(par, w->watcher_size, |
|---|
| 421 | | - e->ethproto, e->invflags & EBT_IPROTO); |
|---|
| 417 | + ntohs(e->ethproto), e->invflags & EBT_IPROTO); |
|---|
| 422 | 418 | if (ret < 0) { |
|---|
| 423 | 419 | module_put(watcher->me); |
|---|
| 424 | 420 | return ret; |
|---|
| .. | .. |
|---|
| 744 | 740 | tgpar.target = target; |
|---|
| 745 | 741 | tgpar.targinfo = t->data; |
|---|
| 746 | 742 | ret = xt_check_target(&tgpar, t->target_size, |
|---|
| 747 | | - e->ethproto, e->invflags & EBT_IPROTO); |
|---|
| 743 | + ntohs(e->ethproto), e->invflags & EBT_IPROTO); |
|---|
| 748 | 744 | if (ret < 0) { |
|---|
| 749 | 745 | module_put(target->me); |
|---|
| 750 | 746 | goto cleanup_watchers; |
|---|
| .. | .. |
|---|
| 1003 | 999 | goto free_iterate; |
|---|
| 1004 | 1000 | } |
|---|
| 1005 | 1001 | |
|---|
| 1006 | | - /* the table doesn't like it */ |
|---|
| 1007 | | - if (t->check && (ret = t->check(newinfo, repl->valid_hooks))) |
|---|
| 1002 | + if (repl->valid_hooks != t->valid_hooks) { |
|---|
| 1003 | + ret = -EINVAL; |
|---|
| 1008 | 1004 | goto free_unlock; |
|---|
| 1005 | + } |
|---|
| 1009 | 1006 | |
|---|
| 1010 | 1007 | if (repl->num_counters && repl->num_counters != t->private->nentries) { |
|---|
| 1011 | 1008 | ret = -EINVAL; |
|---|
| .. | .. |
|---|
| 1050 | 1047 | vfree(table); |
|---|
| 1051 | 1048 | vfree(counterstmp); |
|---|
| 1052 | 1049 | |
|---|
| 1053 | | -#ifdef CONFIG_AUDIT |
|---|
| 1054 | | - if (audit_enabled) { |
|---|
| 1055 | | - audit_log(audit_context(), GFP_KERNEL, |
|---|
| 1056 | | - AUDIT_NETFILTER_CFG, |
|---|
| 1057 | | - "table=%s family=%u entries=%u", |
|---|
| 1058 | | - repl->name, AF_BRIDGE, repl->nentries); |
|---|
| 1059 | | - } |
|---|
| 1060 | | -#endif |
|---|
| 1061 | | - return ret; |
|---|
| 1050 | + audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, |
|---|
| 1051 | + AUDIT_XT_OP_REPLACE, GFP_KERNEL); |
|---|
| 1052 | + return 0; |
|---|
| 1062 | 1053 | |
|---|
| 1063 | 1054 | free_unlock: |
|---|
| 1064 | 1055 | mutex_unlock(&ebt_mutex); |
|---|
| .. | .. |
|---|
| 1073 | 1064 | } |
|---|
| 1074 | 1065 | |
|---|
| 1075 | 1066 | /* replace the table */ |
|---|
| 1076 | | -static int do_replace(struct net *net, const void __user *user, |
|---|
| 1077 | | - unsigned int len) |
|---|
| 1067 | +static int do_replace(struct net *net, sockptr_t arg, unsigned int len) |
|---|
| 1078 | 1068 | { |
|---|
| 1079 | 1069 | int ret, countersize; |
|---|
| 1080 | 1070 | struct ebt_table_info *newinfo; |
|---|
| 1081 | 1071 | struct ebt_replace tmp; |
|---|
| 1082 | 1072 | |
|---|
| 1083 | | - if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
|---|
| 1073 | + if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0) |
|---|
| 1084 | 1074 | return -EFAULT; |
|---|
| 1085 | 1075 | |
|---|
| 1086 | 1076 | if (len != sizeof(tmp) + tmp.entries_size) |
|---|
| .. | .. |
|---|
| 1099 | 1089 | tmp.name[sizeof(tmp.name) - 1] = 0; |
|---|
| 1100 | 1090 | |
|---|
| 1101 | 1091 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; |
|---|
| 1102 | | - newinfo = __vmalloc(sizeof(*newinfo) + countersize, GFP_KERNEL_ACCOUNT, |
|---|
| 1103 | | - PAGE_KERNEL); |
|---|
| 1092 | + newinfo = __vmalloc(sizeof(*newinfo) + countersize, GFP_KERNEL_ACCOUNT); |
|---|
| 1104 | 1093 | if (!newinfo) |
|---|
| 1105 | 1094 | return -ENOMEM; |
|---|
| 1106 | 1095 | |
|---|
| 1107 | 1096 | if (countersize) |
|---|
| 1108 | 1097 | memset(newinfo->counters, 0, countersize); |
|---|
| 1109 | 1098 | |
|---|
| 1110 | | - newinfo->entries = __vmalloc(tmp.entries_size, GFP_KERNEL_ACCOUNT, |
|---|
| 1111 | | - PAGE_KERNEL); |
|---|
| 1099 | + newinfo->entries = __vmalloc(tmp.entries_size, GFP_KERNEL_ACCOUNT); |
|---|
| 1112 | 1100 | if (!newinfo->entries) { |
|---|
| 1113 | 1101 | ret = -ENOMEM; |
|---|
| 1114 | 1102 | goto free_newinfo; |
|---|
| .. | .. |
|---|
| 1134 | 1122 | mutex_lock(&ebt_mutex); |
|---|
| 1135 | 1123 | list_del(&table->list); |
|---|
| 1136 | 1124 | mutex_unlock(&ebt_mutex); |
|---|
| 1125 | + audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries, |
|---|
| 1126 | + AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); |
|---|
| 1137 | 1127 | EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, |
|---|
| 1138 | 1128 | ebt_cleanup_entry, net, NULL); |
|---|
| 1139 | 1129 | if (table->private->nentries) |
|---|
| .. | .. |
|---|
| 1197 | 1187 | if (ret != 0) |
|---|
| 1198 | 1188 | goto free_chainstack; |
|---|
| 1199 | 1189 | |
|---|
| 1200 | | - if (table->check && table->check(newinfo, table->valid_hooks)) { |
|---|
| 1201 | | - ret = -EINVAL; |
|---|
| 1202 | | - goto free_chainstack; |
|---|
| 1203 | | - } |
|---|
| 1204 | | - |
|---|
| 1205 | 1190 | table->private = newinfo; |
|---|
| 1206 | 1191 | rwlock_init(&table->lock); |
|---|
| 1207 | 1192 | mutex_lock(&ebt_mutex); |
|---|
| .. | .. |
|---|
| 1221 | 1206 | mutex_unlock(&ebt_mutex); |
|---|
| 1222 | 1207 | |
|---|
| 1223 | 1208 | WRITE_ONCE(*res, table); |
|---|
| 1224 | | - |
|---|
| 1225 | | - if (!ops) |
|---|
| 1226 | | - return 0; |
|---|
| 1227 | | - |
|---|
| 1228 | 1209 | ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); |
|---|
| 1229 | 1210 | if (ret) { |
|---|
| 1230 | 1211 | __ebt_unregister_table(net, table); |
|---|
| 1231 | 1212 | *res = NULL; |
|---|
| 1232 | 1213 | } |
|---|
| 1233 | 1214 | |
|---|
| 1215 | + audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, |
|---|
| 1216 | + AUDIT_XT_OP_REGISTER, GFP_KERNEL); |
|---|
| 1234 | 1217 | return ret; |
|---|
| 1235 | 1218 | free_unlock: |
|---|
| 1236 | 1219 | mutex_unlock(&ebt_mutex); |
|---|
| .. | .. |
|---|
| 1245 | 1228 | return ret; |
|---|
| 1246 | 1229 | } |
|---|
| 1247 | 1230 | |
|---|
| 1248 | | -void ebt_unregister_table(struct net *net, struct ebt_table *table, |
|---|
| 1249 | | - const struct nf_hook_ops *ops) |
|---|
| 1231 | +static struct ebt_table *__ebt_find_table(struct net *net, const char *name) |
|---|
| 1250 | 1232 | { |
|---|
| 1251 | | - if (ops) |
|---|
| 1233 | + struct ebt_table *t; |
|---|
| 1234 | + |
|---|
| 1235 | + mutex_lock(&ebt_mutex); |
|---|
| 1236 | + |
|---|
| 1237 | + list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) { |
|---|
| 1238 | + if (strcmp(t->name, name) == 0) { |
|---|
| 1239 | + mutex_unlock(&ebt_mutex); |
|---|
| 1240 | + return t; |
|---|
| 1241 | + } |
|---|
| 1242 | + } |
|---|
| 1243 | + |
|---|
| 1244 | + mutex_unlock(&ebt_mutex); |
|---|
| 1245 | + return NULL; |
|---|
| 1246 | +} |
|---|
| 1247 | + |
|---|
| 1248 | +void ebt_unregister_table_pre_exit(struct net *net, const char *name, const struct nf_hook_ops *ops) |
|---|
| 1249 | +{ |
|---|
| 1250 | + struct ebt_table *table = __ebt_find_table(net, name); |
|---|
| 1251 | + |
|---|
| 1252 | + if (table) |
|---|
| 1252 | 1253 | nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); |
|---|
| 1254 | +} |
|---|
| 1255 | +EXPORT_SYMBOL(ebt_unregister_table_pre_exit); |
|---|
| 1256 | + |
|---|
| 1257 | +void ebt_unregister_table(struct net *net, struct ebt_table *table) |
|---|
| 1258 | +{ |
|---|
| 1253 | 1259 | __ebt_unregister_table(net, table); |
|---|
| 1254 | 1260 | } |
|---|
| 1255 | 1261 | |
|---|
| 1256 | 1262 | /* userspace just supplied us with counters */ |
|---|
| 1257 | 1263 | static int do_update_counters(struct net *net, const char *name, |
|---|
| 1258 | | - struct ebt_counter __user *counters, |
|---|
| 1259 | | - unsigned int num_counters, |
|---|
| 1260 | | - const void __user *user, unsigned int len) |
|---|
| 1264 | + struct ebt_counter __user *counters, |
|---|
| 1265 | + unsigned int num_counters, unsigned int len) |
|---|
| 1261 | 1266 | { |
|---|
| 1262 | 1267 | int i, ret; |
|---|
| 1263 | 1268 | struct ebt_counter *tmp; |
|---|
| .. | .. |
|---|
| 1300 | 1305 | return ret; |
|---|
| 1301 | 1306 | } |
|---|
| 1302 | 1307 | |
|---|
| 1303 | | -static int update_counters(struct net *net, const void __user *user, |
|---|
| 1304 | | - unsigned int len) |
|---|
| 1308 | +static int update_counters(struct net *net, sockptr_t arg, unsigned int len) |
|---|
| 1305 | 1309 | { |
|---|
| 1306 | 1310 | struct ebt_replace hlp; |
|---|
| 1307 | 1311 | |
|---|
| 1308 | | - if (copy_from_user(&hlp, user, sizeof(hlp))) |
|---|
| 1312 | + if (copy_from_sockptr(&hlp, arg, sizeof(hlp))) |
|---|
| 1309 | 1313 | return -EFAULT; |
|---|
| 1310 | 1314 | |
|---|
| 1311 | 1315 | if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) |
|---|
| 1312 | 1316 | return -EINVAL; |
|---|
| 1313 | 1317 | |
|---|
| 1314 | 1318 | return do_update_counters(net, hlp.name, hlp.counters, |
|---|
| 1315 | | - hlp.num_counters, user, len); |
|---|
| 1319 | + hlp.num_counters, len); |
|---|
| 1316 | 1320 | } |
|---|
| 1317 | 1321 | |
|---|
| 1318 | 1322 | static inline int ebt_obj_to_user(char __user *um, const char *_name, |
|---|
| .. | .. |
|---|
| 1464 | 1468 | ebt_entry_to_user, entries, tmp.entries); |
|---|
| 1465 | 1469 | } |
|---|
| 1466 | 1470 | |
|---|
| 1467 | | -static int do_ebt_set_ctl(struct sock *sk, |
|---|
| 1468 | | - int cmd, void __user *user, unsigned int len) |
|---|
| 1469 | | -{ |
|---|
| 1470 | | - int ret; |
|---|
| 1471 | | - struct net *net = sock_net(sk); |
|---|
| 1472 | | - |
|---|
| 1473 | | - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
|---|
| 1474 | | - return -EPERM; |
|---|
| 1475 | | - |
|---|
| 1476 | | - switch (cmd) { |
|---|
| 1477 | | - case EBT_SO_SET_ENTRIES: |
|---|
| 1478 | | - ret = do_replace(net, user, len); |
|---|
| 1479 | | - break; |
|---|
| 1480 | | - case EBT_SO_SET_COUNTERS: |
|---|
| 1481 | | - ret = update_counters(net, user, len); |
|---|
| 1482 | | - break; |
|---|
| 1483 | | - default: |
|---|
| 1484 | | - ret = -EINVAL; |
|---|
| 1485 | | - } |
|---|
| 1486 | | - return ret; |
|---|
| 1487 | | -} |
|---|
| 1488 | | - |
|---|
| 1489 | | -static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) |
|---|
| 1490 | | -{ |
|---|
| 1491 | | - int ret; |
|---|
| 1492 | | - struct ebt_replace tmp; |
|---|
| 1493 | | - struct ebt_table *t; |
|---|
| 1494 | | - struct net *net = sock_net(sk); |
|---|
| 1495 | | - |
|---|
| 1496 | | - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
|---|
| 1497 | | - return -EPERM; |
|---|
| 1498 | | - |
|---|
| 1499 | | - if (copy_from_user(&tmp, user, sizeof(tmp))) |
|---|
| 1500 | | - return -EFAULT; |
|---|
| 1501 | | - |
|---|
| 1502 | | - tmp.name[sizeof(tmp.name) - 1] = '\0'; |
|---|
| 1503 | | - |
|---|
| 1504 | | - t = find_table_lock(net, tmp.name, &ret, &ebt_mutex); |
|---|
| 1505 | | - if (!t) |
|---|
| 1506 | | - return ret; |
|---|
| 1507 | | - |
|---|
| 1508 | | - switch (cmd) { |
|---|
| 1509 | | - case EBT_SO_GET_INFO: |
|---|
| 1510 | | - case EBT_SO_GET_INIT_INFO: |
|---|
| 1511 | | - if (*len != sizeof(struct ebt_replace)) { |
|---|
| 1512 | | - ret = -EINVAL; |
|---|
| 1513 | | - mutex_unlock(&ebt_mutex); |
|---|
| 1514 | | - break; |
|---|
| 1515 | | - } |
|---|
| 1516 | | - if (cmd == EBT_SO_GET_INFO) { |
|---|
| 1517 | | - tmp.nentries = t->private->nentries; |
|---|
| 1518 | | - tmp.entries_size = t->private->entries_size; |
|---|
| 1519 | | - tmp.valid_hooks = t->valid_hooks; |
|---|
| 1520 | | - } else { |
|---|
| 1521 | | - tmp.nentries = t->table->nentries; |
|---|
| 1522 | | - tmp.entries_size = t->table->entries_size; |
|---|
| 1523 | | - tmp.valid_hooks = t->table->valid_hooks; |
|---|
| 1524 | | - } |
|---|
| 1525 | | - mutex_unlock(&ebt_mutex); |
|---|
| 1526 | | - if (copy_to_user(user, &tmp, *len) != 0) { |
|---|
| 1527 | | - ret = -EFAULT; |
|---|
| 1528 | | - break; |
|---|
| 1529 | | - } |
|---|
| 1530 | | - ret = 0; |
|---|
| 1531 | | - break; |
|---|
| 1532 | | - |
|---|
| 1533 | | - case EBT_SO_GET_ENTRIES: |
|---|
| 1534 | | - case EBT_SO_GET_INIT_ENTRIES: |
|---|
| 1535 | | - ret = copy_everything_to_user(t, user, len, cmd); |
|---|
| 1536 | | - mutex_unlock(&ebt_mutex); |
|---|
| 1537 | | - break; |
|---|
| 1538 | | - |
|---|
| 1539 | | - default: |
|---|
| 1540 | | - mutex_unlock(&ebt_mutex); |
|---|
| 1541 | | - ret = -EINVAL; |
|---|
| 1542 | | - } |
|---|
| 1543 | | - |
|---|
| 1544 | | - return ret; |
|---|
| 1545 | | -} |
|---|
| 1546 | | - |
|---|
| 1547 | 1471 | #ifdef CONFIG_COMPAT |
|---|
| 1548 | 1472 | /* 32 bit-userspace compatibility definitions. */ |
|---|
| 1549 | 1473 | struct compat_ebt_replace { |
|---|
| .. | .. |
|---|
| 1570 | 1494 | compat_uptr_t ptr; |
|---|
| 1571 | 1495 | } u; |
|---|
| 1572 | 1496 | compat_uint_t match_size; |
|---|
| 1573 | | - compat_uint_t data[0] __attribute__ ((aligned (__alignof__(struct compat_ebt_replace)))); |
|---|
| 1497 | + compat_uint_t data[] __aligned(__alignof__(struct compat_ebt_replace)); |
|---|
| 1574 | 1498 | }; |
|---|
| 1575 | 1499 | |
|---|
| 1576 | 1500 | /* account for possible padding between match_size and ->data */ |
|---|
| .. | .. |
|---|
| 1948 | 1872 | size_kern = match_size; |
|---|
| 1949 | 1873 | module_put(match->me); |
|---|
| 1950 | 1874 | break; |
|---|
| 1951 | | - case EBT_COMPAT_WATCHER: /* fallthrough */ |
|---|
| 1875 | + case EBT_COMPAT_WATCHER: |
|---|
| 1952 | 1876 | case EBT_COMPAT_TARGET: |
|---|
| 1953 | 1877 | wt = xt_request_find_target(NFPROTO_BRIDGE, name, |
|---|
| 1954 | 1878 | mwt->u.revision); |
|---|
| .. | .. |
|---|
| 2077 | 2001 | return ret; |
|---|
| 2078 | 2002 | |
|---|
| 2079 | 2003 | offsets[0] = sizeof(struct ebt_entry); /* matches come first */ |
|---|
| 2080 | | - memcpy(&offsets[1], &entry->watchers_offset, |
|---|
| 2081 | | - sizeof(offsets) - sizeof(offsets[0])); |
|---|
| 2004 | + memcpy(&offsets[1], &entry->offsets, sizeof(entry->offsets)); |
|---|
| 2082 | 2005 | |
|---|
| 2083 | 2006 | if (state->buf_kern_start) { |
|---|
| 2084 | 2007 | buf_start = state->buf_kern_start + state->buf_kern_offset; |
|---|
| .. | .. |
|---|
| 2173 | 2096 | |
|---|
| 2174 | 2097 | |
|---|
| 2175 | 2098 | static int compat_copy_ebt_replace_from_user(struct ebt_replace *repl, |
|---|
| 2176 | | - void __user *user, unsigned int len) |
|---|
| 2099 | + sockptr_t arg, unsigned int len) |
|---|
| 2177 | 2100 | { |
|---|
| 2178 | 2101 | struct compat_ebt_replace tmp; |
|---|
| 2179 | 2102 | int i; |
|---|
| .. | .. |
|---|
| 2181 | 2104 | if (len < sizeof(tmp)) |
|---|
| 2182 | 2105 | return -EINVAL; |
|---|
| 2183 | 2106 | |
|---|
| 2184 | | - if (copy_from_user(&tmp, user, sizeof(tmp))) |
|---|
| 2107 | + if (copy_from_sockptr(&tmp, arg, sizeof(tmp))) |
|---|
| 2185 | 2108 | return -EFAULT; |
|---|
| 2186 | 2109 | |
|---|
| 2187 | 2110 | if (len != sizeof(tmp) + tmp.entries_size) |
|---|
| .. | .. |
|---|
| 2208 | 2131 | return 0; |
|---|
| 2209 | 2132 | } |
|---|
| 2210 | 2133 | |
|---|
| 2211 | | -static int compat_do_replace(struct net *net, void __user *user, |
|---|
| 2212 | | - unsigned int len) |
|---|
| 2134 | +static int compat_do_replace(struct net *net, sockptr_t arg, unsigned int len) |
|---|
| 2213 | 2135 | { |
|---|
| 2214 | 2136 | int ret, i, countersize, size64; |
|---|
| 2215 | 2137 | struct ebt_table_info *newinfo; |
|---|
| .. | .. |
|---|
| 2217 | 2139 | struct ebt_entries_buf_state state; |
|---|
| 2218 | 2140 | void *entries_tmp; |
|---|
| 2219 | 2141 | |
|---|
| 2220 | | - ret = compat_copy_ebt_replace_from_user(&tmp, user, len); |
|---|
| 2142 | + ret = compat_copy_ebt_replace_from_user(&tmp, arg, len); |
|---|
| 2221 | 2143 | if (ret) { |
|---|
| 2222 | 2144 | /* try real handler in case userland supplied needed padding */ |
|---|
| 2223 | | - if (ret == -EINVAL && do_replace(net, user, len) == 0) |
|---|
| 2145 | + if (ret == -EINVAL && do_replace(net, arg, len) == 0) |
|---|
| 2224 | 2146 | ret = 0; |
|---|
| 2225 | 2147 | return ret; |
|---|
| 2226 | 2148 | } |
|---|
| .. | .. |
|---|
| 2311 | 2233 | goto free_entries; |
|---|
| 2312 | 2234 | } |
|---|
| 2313 | 2235 | |
|---|
| 2314 | | -static int compat_update_counters(struct net *net, void __user *user, |
|---|
| 2236 | +static int compat_update_counters(struct net *net, sockptr_t arg, |
|---|
| 2315 | 2237 | unsigned int len) |
|---|
| 2316 | 2238 | { |
|---|
| 2317 | 2239 | struct compat_ebt_replace hlp; |
|---|
| 2318 | 2240 | |
|---|
| 2319 | | - if (copy_from_user(&hlp, user, sizeof(hlp))) |
|---|
| 2241 | + if (copy_from_sockptr(&hlp, arg, sizeof(hlp))) |
|---|
| 2320 | 2242 | return -EFAULT; |
|---|
| 2321 | 2243 | |
|---|
| 2322 | 2244 | /* try real handler in case userland supplied needed padding */ |
|---|
| 2323 | 2245 | if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) |
|---|
| 2324 | | - return update_counters(net, user, len); |
|---|
| 2246 | + return update_counters(net, arg, len); |
|---|
| 2325 | 2247 | |
|---|
| 2326 | 2248 | return do_update_counters(net, hlp.name, compat_ptr(hlp.counters), |
|---|
| 2327 | | - hlp.num_counters, user, len); |
|---|
| 2328 | | -} |
|---|
| 2329 | | - |
|---|
| 2330 | | -static int compat_do_ebt_set_ctl(struct sock *sk, |
|---|
| 2331 | | - int cmd, void __user *user, unsigned int len) |
|---|
| 2332 | | -{ |
|---|
| 2333 | | - int ret; |
|---|
| 2334 | | - struct net *net = sock_net(sk); |
|---|
| 2335 | | - |
|---|
| 2336 | | - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
|---|
| 2337 | | - return -EPERM; |
|---|
| 2338 | | - |
|---|
| 2339 | | - switch (cmd) { |
|---|
| 2340 | | - case EBT_SO_SET_ENTRIES: |
|---|
| 2341 | | - ret = compat_do_replace(net, user, len); |
|---|
| 2342 | | - break; |
|---|
| 2343 | | - case EBT_SO_SET_COUNTERS: |
|---|
| 2344 | | - ret = compat_update_counters(net, user, len); |
|---|
| 2345 | | - break; |
|---|
| 2346 | | - default: |
|---|
| 2347 | | - ret = -EINVAL; |
|---|
| 2348 | | - } |
|---|
| 2349 | | - return ret; |
|---|
| 2249 | + hlp.num_counters, len); |
|---|
| 2350 | 2250 | } |
|---|
| 2351 | 2251 | |
|---|
| 2352 | 2252 | static int compat_do_ebt_get_ctl(struct sock *sk, int cmd, |
|---|
| .. | .. |
|---|
| 2357 | 2257 | struct ebt_table *t; |
|---|
| 2358 | 2258 | struct net *net = sock_net(sk); |
|---|
| 2359 | 2259 | |
|---|
| 2360 | | - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
|---|
| 2361 | | - return -EPERM; |
|---|
| 2362 | | - |
|---|
| 2363 | | - /* try real handler in case userland supplied needed padding */ |
|---|
| 2364 | | - if ((cmd == EBT_SO_GET_INFO || |
|---|
| 2365 | | - cmd == EBT_SO_GET_INIT_INFO) && *len != sizeof(tmp)) |
|---|
| 2366 | | - return do_ebt_get_ctl(sk, cmd, user, len); |
|---|
| 2260 | + if ((cmd == EBT_SO_GET_INFO || cmd == EBT_SO_GET_INIT_INFO) && |
|---|
| 2261 | + *len != sizeof(struct compat_ebt_replace)) |
|---|
| 2262 | + return -EINVAL; |
|---|
| 2367 | 2263 | |
|---|
| 2368 | 2264 | if (copy_from_user(&tmp, user, sizeof(tmp))) |
|---|
| 2369 | 2265 | return -EFAULT; |
|---|
| .. | .. |
|---|
| 2426 | 2322 | } |
|---|
| 2427 | 2323 | #endif |
|---|
| 2428 | 2324 | |
|---|
| 2325 | +static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) |
|---|
| 2326 | +{ |
|---|
| 2327 | + struct net *net = sock_net(sk); |
|---|
| 2328 | + struct ebt_replace tmp; |
|---|
| 2329 | + struct ebt_table *t; |
|---|
| 2330 | + int ret; |
|---|
| 2331 | + |
|---|
| 2332 | + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
|---|
| 2333 | + return -EPERM; |
|---|
| 2334 | + |
|---|
| 2335 | +#ifdef CONFIG_COMPAT |
|---|
| 2336 | + /* try real handler in case userland supplied needed padding */ |
|---|
| 2337 | + if (in_compat_syscall() && |
|---|
| 2338 | + ((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) || |
|---|
| 2339 | + *len != sizeof(tmp))) |
|---|
| 2340 | + return compat_do_ebt_get_ctl(sk, cmd, user, len); |
|---|
| 2341 | +#endif |
|---|
| 2342 | + |
|---|
| 2343 | + if (copy_from_user(&tmp, user, sizeof(tmp))) |
|---|
| 2344 | + return -EFAULT; |
|---|
| 2345 | + |
|---|
| 2346 | + tmp.name[sizeof(tmp.name) - 1] = '\0'; |
|---|
| 2347 | + |
|---|
| 2348 | + t = find_table_lock(net, tmp.name, &ret, &ebt_mutex); |
|---|
| 2349 | + if (!t) |
|---|
| 2350 | + return ret; |
|---|
| 2351 | + |
|---|
| 2352 | + switch (cmd) { |
|---|
| 2353 | + case EBT_SO_GET_INFO: |
|---|
| 2354 | + case EBT_SO_GET_INIT_INFO: |
|---|
| 2355 | + if (*len != sizeof(struct ebt_replace)) { |
|---|
| 2356 | + ret = -EINVAL; |
|---|
| 2357 | + mutex_unlock(&ebt_mutex); |
|---|
| 2358 | + break; |
|---|
| 2359 | + } |
|---|
| 2360 | + if (cmd == EBT_SO_GET_INFO) { |
|---|
| 2361 | + tmp.nentries = t->private->nentries; |
|---|
| 2362 | + tmp.entries_size = t->private->entries_size; |
|---|
| 2363 | + tmp.valid_hooks = t->valid_hooks; |
|---|
| 2364 | + } else { |
|---|
| 2365 | + tmp.nentries = t->table->nentries; |
|---|
| 2366 | + tmp.entries_size = t->table->entries_size; |
|---|
| 2367 | + tmp.valid_hooks = t->table->valid_hooks; |
|---|
| 2368 | + } |
|---|
| 2369 | + mutex_unlock(&ebt_mutex); |
|---|
| 2370 | + if (copy_to_user(user, &tmp, *len) != 0) { |
|---|
| 2371 | + ret = -EFAULT; |
|---|
| 2372 | + break; |
|---|
| 2373 | + } |
|---|
| 2374 | + ret = 0; |
|---|
| 2375 | + break; |
|---|
| 2376 | + |
|---|
| 2377 | + case EBT_SO_GET_ENTRIES: |
|---|
| 2378 | + case EBT_SO_GET_INIT_ENTRIES: |
|---|
| 2379 | + ret = copy_everything_to_user(t, user, len, cmd); |
|---|
| 2380 | + mutex_unlock(&ebt_mutex); |
|---|
| 2381 | + break; |
|---|
| 2382 | + |
|---|
| 2383 | + default: |
|---|
| 2384 | + mutex_unlock(&ebt_mutex); |
|---|
| 2385 | + ret = -EINVAL; |
|---|
| 2386 | + } |
|---|
| 2387 | + |
|---|
| 2388 | + return ret; |
|---|
| 2389 | +} |
|---|
| 2390 | + |
|---|
| 2391 | +static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, |
|---|
| 2392 | + unsigned int len) |
|---|
| 2393 | +{ |
|---|
| 2394 | + struct net *net = sock_net(sk); |
|---|
| 2395 | + int ret; |
|---|
| 2396 | + |
|---|
| 2397 | + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
|---|
| 2398 | + return -EPERM; |
|---|
| 2399 | + |
|---|
| 2400 | + switch (cmd) { |
|---|
| 2401 | + case EBT_SO_SET_ENTRIES: |
|---|
| 2402 | +#ifdef CONFIG_COMPAT |
|---|
| 2403 | + if (in_compat_syscall()) |
|---|
| 2404 | + ret = compat_do_replace(net, arg, len); |
|---|
| 2405 | + else |
|---|
| 2406 | +#endif |
|---|
| 2407 | + ret = do_replace(net, arg, len); |
|---|
| 2408 | + break; |
|---|
| 2409 | + case EBT_SO_SET_COUNTERS: |
|---|
| 2410 | +#ifdef CONFIG_COMPAT |
|---|
| 2411 | + if (in_compat_syscall()) |
|---|
| 2412 | + ret = compat_update_counters(net, arg, len); |
|---|
| 2413 | + else |
|---|
| 2414 | +#endif |
|---|
| 2415 | + ret = update_counters(net, arg, len); |
|---|
| 2416 | + break; |
|---|
| 2417 | + default: |
|---|
| 2418 | + ret = -EINVAL; |
|---|
| 2419 | + } |
|---|
| 2420 | + return ret; |
|---|
| 2421 | +} |
|---|
| 2422 | + |
|---|
| 2429 | 2423 | static struct nf_sockopt_ops ebt_sockopts = { |
|---|
| 2430 | 2424 | .pf = PF_INET, |
|---|
| 2431 | 2425 | .set_optmin = EBT_BASE_CTL, |
|---|
| 2432 | 2426 | .set_optmax = EBT_SO_SET_MAX + 1, |
|---|
| 2433 | 2427 | .set = do_ebt_set_ctl, |
|---|
| 2434 | | -#ifdef CONFIG_COMPAT |
|---|
| 2435 | | - .compat_set = compat_do_ebt_set_ctl, |
|---|
| 2436 | | -#endif |
|---|
| 2437 | 2428 | .get_optmin = EBT_BASE_CTL, |
|---|
| 2438 | 2429 | .get_optmax = EBT_SO_GET_MAX + 1, |
|---|
| 2439 | 2430 | .get = do_ebt_get_ctl, |
|---|
| 2440 | | -#ifdef CONFIG_COMPAT |
|---|
| 2441 | | - .compat_get = compat_do_ebt_get_ctl, |
|---|
| 2442 | | -#endif |
|---|
| 2443 | 2431 | .owner = THIS_MODULE, |
|---|
| 2444 | 2432 | }; |
|---|
| 2445 | 2433 | |
|---|