static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop) { const struct udphdr *udp = hdr; const struct ip6t_multiport *multiinfo = matchinfo; /* Must be big enough to read ports. */ if (offset == 0 && datalen < sizeof(struct udphdr)) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ duprintf("ip6t_multiport:" " Dropping evil offset=0 tinygram.\n"); *hotdrop = 1; return 0; } /* Must not be a fragment. */ return !offset && ports_match(multiinfo->ports, multiinfo->flags, multiinfo->count, ntohs(udp->source), ntohs(udp->dest)); }
static int udp_match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct xt_match *match, const void *matchinfo, int offset, unsigned int protoff, int *hotdrop) { struct udphdr _udph, *uh; const struct xt_udp *udpinfo = matchinfo; /* Must not be a fragment. */ if (offset) return 0; uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph); if (uh == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ duprintf("Dropping evil UDP tinygram.\n"); *hotdrop = 1; return 0; } return port_match(udpinfo->spts[0], udpinfo->spts[1], ntohs(uh->source), !!(udpinfo->invflags & XT_UDP_INV_SRCPT)) && port_match(udpinfo->dpts[0], udpinfo->dpts[1], ntohs(uh->dest), !!(udpinfo->invflags & XT_UDP_INV_DSTPT)); }
static bool esp_mt(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct xt_match *match, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { const struct ip_esp_hdr *eh; struct ip_esp_hdr _esp; const struct xt_esp *espinfo = matchinfo; /* Must not be a fragment. */ if (offset) return false; eh = skb_header_pointer(skb, protoff, sizeof(_esp), &_esp); if (eh == NULL) { /* We've been asked to examine this packet, and we * can't. Hence, no choice but to drop. */ duprintf("Dropping evil ESP tinygram.\n"); *hotdrop = true; return false; } return spi_match(espinfo->spis[0], espinfo->spis[1], ntohl(eh->spi), !!(espinfo->invflags & XT_ESP_INV_SPI)); }
static int match_v1(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) const void *hdr, u_int16_t datalen, #endif int *hotdrop) { u16 _ports[2], *pptr; const struct ipt_multiport_v1 *multiinfo = matchinfo; if (offset) return 0; pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4, sizeof(_ports), _ports); if (pptr == NULL) { /* We've been asked to examine this packet, and we * can't. Hence, no choice but to drop. */ duprintf("ipt_multiport:" " Dropping evil offset=0 tinygram.\n"); *hotdrop = 1; return 0; } return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); }
static int tcp_find_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff, unsigned int optlen, int invert, int *hotdrop) { /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ u_int8_t _opt[60 - sizeof(struct tcphdr)], *op; unsigned int i; duprintf("tcp_match: finding option\n"); if (!optlen) return invert; /* If we don't have the whole header, drop packet. */ op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr), optlen, _opt); if (op == NULL) { *hotdrop = 1; return 0; } for (i = 0; i < optlen; ) { if (op[i] == option) return !invert; if (op[i] < 2) i++; else i += op[i+1]?:1; } return invert; }
/* Returns 1 if the port is matched by the test, 0 otherwise. */ static inline bool ports_match_v1(const struct xt_multiport_v1 *minfo, u_int16_t src, u_int16_t dst) { unsigned int i; u_int16_t s, e; for (i = 0; i < minfo->count; i++) { s = minfo->ports[i]; if (minfo->pflags[i]) { /* range port matching */ e = minfo->ports[++i]; duprintf("src or dst matches with %d-%d?\n", s, e); if (minfo->flags == XT_MULTIPORT_SOURCE && src >= s && src <= e) return true ^ minfo->invert; if (minfo->flags == XT_MULTIPORT_DESTINATION && dst >= s && dst <= e) return true ^ minfo->invert; if (minfo->flags == XT_MULTIPORT_EITHER && ((dst >= s && dst <= e) || (src >= s && src <= e))) return true ^ minfo->invert; } else { /* exact port matching */ duprintf("src or dst matches with %d?\n", s); if (minfo->flags == XT_MULTIPORT_SOURCE && src == s) return true ^ minfo->invert; if (minfo->flags == XT_MULTIPORT_DESTINATION && dst == s) return true ^ minfo->invert; if (minfo->flags == XT_MULTIPORT_EITHER && (src == s || dst == s)) return true ^ minfo->invert; } } return minfo->invert; }
static int CVE_2011_1171_linux2_6_23_do_replace(void __user *user, unsigned int len) { int ret; struct ipt_replace tmp; struct xt_table_info *newinfo; void *loc_cpu_entry; if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) return -EFAULT; /* Hack: Causes ipchains to give correct error msg --RR */ if (len != sizeof(tmp) + tmp.size) return -ENOPROTOOPT; /* overflow check */ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS - SMP_CACHE_BYTES) return -ENOMEM; if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; newinfo = xt_alloc_table_info(tmp.size); if (!newinfo) return -ENOMEM; /* choose the copy that is our node/cpu */ loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), tmp.size) != 0) { ret = -EFAULT; goto free_newinfo; } ret = translate_table(tmp.name, tmp.valid_hooks, newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, tmp.hook_entry, tmp.underflow); if (ret != 0) goto free_newinfo; duprintf("ip_tables: Translated table\n"); ret = __CVE_2011_1171_linux2_6_23_do_replace(tmp.name, tmp.valid_hooks, newinfo, tmp.num_counters, tmp.counters); if (ret) goto free_newinfo_untrans; return 0; free_newinfo_untrans: IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL); free_newinfo: xt_free_table_info(newinfo); return ret; }
static inline int ip_fw_domatch(struct ip_fwkernel *f, struct iphdr *ip, const char *rif, const ip_chainlabel label, struct sk_buff *skb, unsigned int slot, __u16 src_port, __u16 dst_port, unsigned int count, int tcpsyn) { f->counters[slot].bcnt+=ntohs(ip->tot_len); f->counters[slot].pcnt++; if (f->ipfw.fw_flg & IP_FW_F_PRN) { dump_packet(ip,rif,f,label,src_port,dst_port,count,tcpsyn); } ip->tos = (ip->tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor; /* This functionality is useless in stock 2.0.x series, but we don't * discard the mark thing altogether, to avoid breaking ipchains (and, * more importantly, the ipfwadm wrapper) --PR */ if (f->ipfw.fw_flg & IP_FW_F_MARKABS) { skb->nfmark = f->ipfw.fw_mark; } else { skb->nfmark += f->ipfw.fw_mark; } if (f->ipfw.fw_flg & IP_FW_F_NETLINK) { #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) size_t len = min_t(unsigned int, f->ipfw.fw_outputsize, ntohs(ip->tot_len)) + sizeof(__u32) + sizeof(skb->nfmark) + IFNAMSIZ; struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC); duprintf("Sending packet out NETLINK (length = %u).\n", (unsigned int)len); if (outskb) { /* Prepend length, mark & interface */ skb_put(outskb, len); *((__u32 *)outskb->data) = (__u32)len; *((__u32 *)(outskb->data+sizeof(__u32))) = skb->nfmark; strcpy(outskb->data+sizeof(__u32)*2, rif); memcpy(outskb->data+sizeof(__u32)*2+IFNAMSIZ, ip, len-(sizeof(__u32)*2+IFNAMSIZ)); netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_ATOMIC); } else { #endif if (net_ratelimit()) printk(KERN_WARNING "ip_fw: packet drop due to " "netlink failure\n"); return 0; #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) } #endif }
static bool checkentry(const struct xt_mtchk_param *par) { const struct xt_esp *espinfo = par->matchinfo; if (espinfo->invflags & ~XT_ESP_INV_MASK) { duprintf("xt_esp: unknown flags %X\n", espinfo->invflags); return false; } return true; }
/* Called when user tries to insert an entry of this type. */ static bool esp_mt_check(const char *tablename, const void *ip_void, const struct xt_match *match, void *matchinfo, unsigned int hook_mask) { const struct xt_esp *espinfo = matchinfo; if (espinfo->invflags & ~XT_ESP_INV_MASK) { duprintf("xt_esp: unknown flags %X\n", espinfo->invflags); return false; } return true; }
static bool match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct xt_match *match, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { const struct xt_sctp_info *info = matchinfo; sctp_sctphdr_t _sh, *sh; if (offset) { duprintf("Dropping non-first fragment.. FIXME\n"); return false; } sh = skb_header_pointer(skb, protoff, sizeof(_sh), &_sh); if (sh == NULL) { duprintf("Dropping evil TCP offset=0 tinygram.\n"); *hotdrop = true; return false; } duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest)); return SCCHECK(ntohs(sh->source) >= info->spts[0] && ntohs(sh->source) <= info->spts[1], XT_SCTP_SRC_PORTS, info->flags, info->invflags) && SCCHECK(ntohs(sh->dest) >= info->dpts[0] && ntohs(sh->dest) <= info->dpts[1], XT_SCTP_DEST_PORTS, info->flags, info->invflags) && SCCHECK(match_packet(skb, protoff + sizeof (sctp_sctphdr_t), info, hotdrop), XT_SCTP_CHUNK_TYPES, info->flags, info->invflags); }
/* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, const void *ip_void, const struct xt_match *match, void *matchinfo, unsigned int matchinfosize, unsigned int hook_mask) { const struct ipt_ah *ahinfo = matchinfo; /* Must specify no unknown invflags */ if (ahinfo->invflags & ~IPT_AH_INV_MASK) { duprintf("ipt_ah: unknown flags %X\n", ahinfo->invflags); return 0; } return 1; }
/* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, const void *ip_void, const struct xt_match *match, void *matchinfo, unsigned int matchinfosize, unsigned int hook_mask) { const struct xt_esp *espinfo = matchinfo; if (espinfo->invflags & ~XT_ESP_INV_MASK) { duprintf("xt_esp: unknown flags %X\n", espinfo->invflags); return 0; } return 1; }
/* * Return the drive letter and volume label * If the drive doesn't have a volume assigned, space is returned for the letter */ BOOL GetDriveLabel(DWORD DriveIndex, char* letters, char** label) { HANDLE hPhysical; DWORD size; static char VolumeLabel[MAX_PATH + 1]; char DrivePath[] = "#:\\", AutorunPath[] = "#:\\autorun.inf", *AutorunLabel = NULL; *label = STR_NO_LABEL; if (!GetDriveLetters(DriveIndex, letters)) return FALSE; if (letters[0] == 0) { // Drive without volume assigned - always enabled return TRUE; } // We only care about an autorun.inf if we have a single volume AutorunPath[0] = letters[0]; DrivePath[0] = letters[0]; // Try to read an extended label from autorun first. Fallback to regular label if not found. // In the case of card readers with no card, users can get an annoying popup asking them // to insert media. Use IOCTL_STORAGE_CHECK_VERIFY to prevent this hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE); if (DeviceIoControl(hPhysical, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &size, NULL)) AutorunLabel = get_token_data_file("label", AutorunPath); else if (GetLastError() == ERROR_NOT_READY) uprintf("Ignoring autorun.inf label for drive %c: %s\n", letters[0], (HRESULT_CODE(GetLastError()) == ERROR_NOT_READY)?"No media":WindowsErrorString()); safe_closehandle(hPhysical); if (AutorunLabel != NULL) { uprintf("Using autorun.inf label for drive %c: '%s'\n", letters[0], AutorunLabel); safe_strcpy(VolumeLabel, sizeof(VolumeLabel), AutorunLabel); safe_free(AutorunLabel); *label = VolumeLabel; } else if (GetVolumeInformationU(DrivePath, VolumeLabel, ARRAYSIZE(VolumeLabel), NULL, NULL, NULL, NULL, 0) && (VolumeLabel[0] != 0)) { *label = VolumeLabel; } else { duprintf("Failed to read label: %s", WindowsErrorString()); } return TRUE; }
static bool match_v1(const struct sk_buff *skb, struct xt_action_param *par) { __be16 _ports[2], *pptr; const struct xt_multiport_v1 *multiinfo = par->matchinfo; if (par->fragoff != 0) return 0; pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports); if (pptr == NULL) { /* We've been asked to examine this packet, and we * can't. Hence, no choice but to drop. */ duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n"); par->hotdrop = true; return 0; } return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); }
static bool match(const struct sk_buff *skb, struct xt_action_param *par) { struct ip_esp_hdr _esp, *eh; const struct xt_esp *espinfo = par->matchinfo; /* Must not be a fragment. */ if (par->fragoff != 0) return false; eh = skb_header_pointer(skb, par->thoff, sizeof(_esp), &_esp); if (eh == NULL) { /* We've been asked to examine this packet, and we * can't. Hence, no choice but to drop. */ duprintf("Dropping evil ESP tinygram.\n"); par->hotdrop = true; return false; } return spi_match(espinfo->spis[0], espinfo->spis[1], ntohl(eh->spi), !!(espinfo->invflags & XT_ESP_INV_SPI)); }
static bool multiport_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) { const __be16 *pptr; __be16 _ports[2]; const struct xt_multiport *multiinfo = par->matchinfo; if (par->fragoff != 0) return false; pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports); if (pptr == NULL) { /* We've been asked to examine this packet, and we * can't. Hence, no choice but to drop. */ duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n"); *par->hotdrop = true; return false; } return ports_match_v0(multiinfo->ports, multiinfo->flags, multiinfo->count, ntohs(pptr[0]), ntohs(pptr[1])); }
/* * Search for a specific 'src' substring data for all occurrences of 'token', and replace * it with 'rep'. File can be ANSI or UNICODE and is overwritten. Parameters are UTF-8. * The parsed line is of the form: [ ]token[ ]data * Returns a pointer to rep if replacement occurred, NULL otherwise */ char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix) { const wchar_t* outmode[] = { L"w", L"w, ccs=UTF-8", L"w, ccs=UTF-16LE" }; wchar_t *wtoken = NULL, *wfilename = NULL, *wtmpname = NULL, *wsrc = NULL, *wrep = NULL, bom = 0; wchar_t buf[1024], *torep; FILE *fd_in = NULL, *fd_out = NULL; size_t i, size; int mode = 0; char *ret = NULL, tmp[2]; if ((filename == NULL) || (token == NULL) || (src == NULL) || (rep == NULL)) return NULL; if ((filename[0] == 0) || (token[0] == 0) || (src[0] == 0) || (rep[0] == 0)) return NULL; if (strcmp(src, rep) == 0) // No need for processing is source is same as replacement return NULL; wfilename = utf8_to_wchar(filename); if (wfilename == NULL) { uprintf("Could not convert '%s' to UTF-16\n", filename); goto out; } wtoken = utf8_to_wchar(token); if (wfilename == NULL) { uprintf("Could not convert '%s' to UTF-16\n", token); goto out; } wsrc = utf8_to_wchar(src); if (wsrc == NULL) { uprintf("Could not convert '%s' to UTF-16\n", src); goto out; } wrep = utf8_to_wchar(rep); if (wsrc == NULL) { uprintf("Could not convert '%s' to UTF-16\n", rep); goto out; } fd_in = _wfopen(wfilename, L"r, ccs=UNICODE"); if (fd_in == NULL) { uprintf("Could not open file '%s'\n", filename); goto out; } // Check the input file's BOM and create an output file with the same if (fread(&bom, sizeof(bom), 1, fd_in) != 1) { uprintf("Could not read file '%s'\n", filename); goto out; } switch(bom) { case 0xFEFF: mode = 2; // UTF-16 (LE) break; case 0xBBEF: // Yeah, the UTF-8 BOM is really 0xEF,0xBB,0xBF, but mode = 1; // find me a non UTF-8 file that actually begins with "ï»" break; default: mode = 0; // ANSI break; } fseek(fd_in, 0, SEEK_SET); duprintf("'%s' was detected as %s\n", filename, (mode==0)?"ANSI/UTF8 (no BOM)":((mode==1)?"UTF8 (with BOM)":"UTF16 (with BOM")); wtmpname = (wchar_t*)calloc(wcslen(wfilename)+2, sizeof(wchar_t)); if (wtmpname == NULL) { uprintf("Could not allocate space for temporary output name\n"); goto out; } wcscpy(wtmpname, wfilename); wtmpname[wcslen(wtmpname)] = '~'; fd_out = _wfopen(wtmpname, outmode[mode]); if (fd_out == NULL) { uprintf("Could not open temporary output file '%s~'\n", filename); goto out; } // Process individual lines. NUL is always appended. while (fgetws(buf, ARRAYSIZE(buf), fd_in) != NULL) { i = 0; // Skip leading spaces i += wcsspn(&buf[i], wspace); // Our token should begin a line if (_wcsnicmp(&buf[i], wtoken, wcslen(wtoken)) != 0) { fputws(buf, fd_out); continue; } // Token was found, move past token i += strlen(token); // Skip spaces i += wcsspn(&buf[i], wspace); torep = wcsstr(&buf[i], wsrc); if (torep == NULL) { fputws(buf, fd_out); continue; } i = (torep-buf) + wcslen(wsrc); *torep = 0; fwprintf(fd_out, L"%s%s%s", buf, wrep, &buf[i]); ret = (char*)rep; } out: if (fd_in != NULL) fclose(fd_in); if (fd_out != NULL) fclose(fd_out); // If a replacement occurred, delete existing file and use the new one if (ret != NULL) { // We're in Windows text mode => Remove CRs if requested fd_in = _wfopen(wtmpname, L"rb"); fd_out = _wfopen(wfilename, L"wb"); // Don't check fds if ((fd_in != NULL) && (fd_out != NULL)) { size = (mode==2)?2:1; while(fread(tmp, size, 1, fd_in) == 1) { if ((!dos2unix) || (tmp[0] != 0x0D)) fwrite(tmp, size, 1, fd_out); } fclose(fd_in); fclose(fd_out); } else { uprintf("Could not write '%s' - original file has been left unmodified.\n", filename); ret = NULL; if (fd_in != NULL) fclose(fd_in); if (fd_out != NULL) fclose(fd_out); } } if (wtmpname != NULL) _wunlink(wtmpname); safe_free(wfilename); safe_free(wtmpname); safe_free(wtoken); safe_free(wsrc); safe_free(wrep); return ret; }
static inline bool match_packet(const struct sk_buff *skb, unsigned int offset, const struct xt_sctp_info *info, bool *hotdrop) { u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)]; const sctp_chunkhdr_t *sch; sctp_chunkhdr_t _sch; int chunk_match_type = info->chunk_match_type; const struct xt_sctp_flag_info *flag_info = info->flag_info; int flag_count = info->flag_count; #ifdef DEBUG_SCTP int i = 0; #endif if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) SCTP_CHUNKMAP_COPY(chunkmapcopy, info->chunkmap); do { sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch); if (sch == NULL || sch->length == 0) { duprintf("Dropping invalid SCTP packet.\n"); *hotdrop = true; return false; } duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", ++i, offset, sch->type, htons(sch->length), sch->flags); offset += (ntohs(sch->length) + 3) & ~3; duprintf("skb->len: %d\toffset: %d\n", skb->len, offset); if (SCTP_CHUNKMAP_IS_SET(info->chunkmap, sch->type)) { switch (chunk_match_type) { case SCTP_CHUNK_MATCH_ANY: if (match_flags(flag_info, flag_count, sch->type, sch->flags)) { return true; } break; case SCTP_CHUNK_MATCH_ALL: if (match_flags(flag_info, flag_count, sch->type, sch->flags)) SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type); break; case SCTP_CHUNK_MATCH_ONLY: if (!match_flags(flag_info, flag_count, sch->type, sch->flags)) return false; break; } } else { switch (chunk_match_type) { case SCTP_CHUNK_MATCH_ONLY: return false; } } } while (offset < skb->len); switch (chunk_match_type) { case SCTP_CHUNK_MATCH_ALL: return SCTP_CHUNKMAP_IS_CLEAR(chunkmapcopy); case SCTP_CHUNK_MATCH_ANY: return false; case SCTP_CHUNK_MATCH_ONLY: return true; } /* This will never be reached, but required to stop compiler whine */ return false; }
static int tcp_match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct xt_match *match, const void *matchinfo, int offset, unsigned int protoff, int *hotdrop) { struct tcphdr _tcph, *th; const struct xt_tcp *tcpinfo = matchinfo; if (offset) { /* To quote Alan: Don't allow a fragment of TCP 8 bytes in. Nobody normal causes this. Its a cracker trying to break in by doing a flag overwrite to pass the direction checks. */ if (offset == 1) { duprintf("Dropping evil TCP offset=1 frag.\n"); *hotdrop = 1; } /* Must not be a fragment. */ return 0; } #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg)) th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); if (th == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ duprintf("Dropping evil TCP offset=0 tinygram.\n"); *hotdrop = 1; return 0; } if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1], ntohs(th->source), !!(tcpinfo->invflags & XT_TCP_INV_SRCPT))) return 0; if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], ntohs(th->dest), !!(tcpinfo->invflags & XT_TCP_INV_DSTPT))) return 0; if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask) == tcpinfo->flg_cmp, XT_TCP_INV_FLAGS)) return 0; if (tcpinfo->option) { if (th->doff * 4 < sizeof(_tcph)) { *hotdrop = 1; return 0; } if (!tcp_find_option(tcpinfo->option, skb, protoff, th->doff*4 - sizeof(_tcph), tcpinfo->invflags & XT_TCP_INV_OPTION, hotdrop)) return 0; } return 1; }
/* * This attempts to detect whether a drive is an USB HDD or an USB Flash Drive (UFD). * A positive score means that we think it's an USB HDD, zero or negative means that * we think it's an UFD. * * This is done so that, if someone already has an USB HDD plugged in (say as a * backup drive) and plugs an UFD we *try* to do what we can to avoid them formatting * that drive by mistake. * However, because there is no foolproof (let alone easy) way to differentiate UFDs * from HDDs, thanks to every manufacturer, Microsoft, and their mothers, making it * exceedingly troublesome to find what type of hardware we are actually accessing, * you are expected to pay heed to the following: * * WARNING: NO PROMISE IS MADE ABOUT THIS ALGORITHM BEING ABLE TO CORRECTLY * DIFFERENTIATE AN USB HDD FROM AN USB FLASH DRIVE. MOREOVER, YOU ARE REMINDED THAT * THE LICENSE OF THIS APPLICATION MAKES NO PROMISE ABOUT AVOIDING DATA LOSS EITHER * (PROVIDED "AS IS"). * THUS, IF DATA LOSS IS INCURRED DUE TO THIS, OR ANY OTHER PART OF THIS APPLICATION, * NOT BEHAVING IN THE MANNER YOU EXPECTED, THE RESPONSIBILITY IS ENTIRELY ON YOU! * * What you have below, then, is our *current best guess* at differentiating UFDs * from HDDs. But short of a crystal ball, this remains just a guess, which may be * way off mark. Still, you are also reminded that Rufus does produce PROMINENT * warnings before you format a drive, and also provides extensive info about the * drive (from the tooltips and the log) => PAY ATTENTION TO THESE OR PAY THE PRICE! * * But let me just elaborate further on why differentiating UFDs from HDDs is not as * 'simple' as it seems: * - many USB flash drives manufacturer will present UFDs as non-removable, which used * to be reserved for HDDs => we can't use that as differentiator. * - some UFDs (SanDisk Extreme) have added S.M.A.R.T. support, which also used to be * reserved for HDDs => can't use that either * - even if S.M.A.R.T. was enough, not all USB->IDE or USB->SATA bridges support ATA * passthrough, which is required S.M.A.R.T. data, and each manufacturer of an * USB<->(S)ATA bridge seem to have their own method of implementing passthrough. * - SSDs have also changed the deal completely, as you can get something that looks * like Flash but that is really an HDD. * - Some manufacturers (eg. verbatim) provide both USB Flash Drives and USB HDDs, so * we can't exactly use the VID to say for sure what we're looking at. * - Finally, Microsoft is absolutely no help either (which is kind of understandable * from the above) => there is no magic API we can query that will tell us what we're * really looking at. */ int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid) { int score = 0; size_t i, mlen, ilen; BOOL wc; uint64_t drive_size; // Boost the score if fixed, as these are *generally* HDDs // NB: Due to a Windows API limitation, drives with no mounted partition will never have DRIVE_FIXED if (GetDriveTypeFromIndex(DriveIndex) == DRIVE_FIXED) score += 3; // Adjust the score depending on the size drive_size = GetDriveSize(DriveIndex); if (drive_size > 512*GB) score += 10; else if (drive_size < 8*GB) score -= 10; // Check the string against well known HDD identifiers if (strid != NULL) { ilen = strlen(strid); for (i=0; i<ARRAYSIZE(str_score); i++) { mlen = strlen(str_score[i].name); if (mlen > ilen) break; wc = (str_score[i].name[mlen-1] == '#'); if ( (_strnicmp(strid, str_score[i].name, mlen-((wc)?1:0)) == 0) && ((!wc) || ((strid[mlen] >= '0') && (strid[mlen] <= '9'))) ) { score += str_score[i].score; break; } } } // Adjust for oddball devices if (strid != NULL) { for (i=0; i<ARRAYSIZE(str_adjust); i++) if (strstr(strid, str_adjust[i].name) != NULL) score += str_adjust[i].score; } // Check against known VIDs for (i=0; i<ARRAYSIZE(vid_score); i++) { if (vid == vid_score[i].vid) { score += vid_score[i].score; break; } } // Check against known VID:PIDs for (i=0; i<ARRAYSIZE(vidpid_score); i++) { if ((vid == vidpid_score[i].vid) && (pid == vidpid_score[i].pid)) { score += vidpid_score[i].score; break; } } // TODO: try to perform inquiry if below a specific threshold (Verbatim, etc)? duprintf(" Score: %d\n", score); return score; }