Wed Jul 25 22:07:59 2018 UTC ()
Avoid undefined behavior semantics in msdosfs_fat.c

Do not change signedness bit with left shift.
While there avoid signed integer overflow.
Address both issues with using unsigned type.

msdosfs_fat.c:512:42, left shift of 1 by 31 places cannot be represented in type 'int'
msdosfs_fat.c:521:44, left shift of 1 by 31 places cannot be represented in type 'int'
msdosfs_fat.c:744:14, left shift of 1 by 31 places cannot be represented in type 'int'
msdosfs_fat.c:744:24, signed integer overflow: -2147483648 - 1 cannot be represented in type 'int [20]'
msdosfs_fat.c:840:13, left shift of 1 by 31 places cannot be represented in type 'int'
msdosfs_fat.c:840:36, signed integer overflow: -2147483648 - 1 cannot be represented in type 'int [20]'

Detected with micro-UBSan in the user mode.


(kamil)
diff -r1.32 -r1.33 src/sys/fs/msdosfs/msdosfs_fat.c

cvs diff -r1.32 -r1.33 src/sys/fs/msdosfs/msdosfs_fat.c (expand / switch to unified diff)

--- src/sys/fs/msdosfs/msdosfs_fat.c 2018/01/27 03:54:01 1.32
+++ src/sys/fs/msdosfs/msdosfs_fat.c 2018/07/25 22:07:59 1.33
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: msdosfs_fat.c,v 1.32 2018/01/27 03:54:01 sevan Exp $ */ 1/* $NetBSD: msdosfs_fat.c,v 1.33 2018/07/25 22:07:59 kamil Exp $ */
2 2
3/*- 3/*-
4 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 4 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
5 * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 5 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
6 * All rights reserved. 6 * All rights reserved.
7 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 7 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
@@ -42,27 +42,27 @@ @@ -42,27 +42,27 @@
42 * The author supplies this software to be publicly redistributed on the 42 * The author supplies this software to be publicly redistributed on the
43 * understanding that the author is not responsible for the correct 43 * understanding that the author is not responsible for the correct
44 * functioning of this software in any circumstances and is not liable for 44 * functioning of this software in any circumstances and is not liable for
45 * any damages caused by this software. 45 * any damages caused by this software.
46 * 46 *
47 * October 1992 47 * October 1992
48 */ 48 */
49 49
50#if HAVE_NBTOOL_CONFIG_H 50#if HAVE_NBTOOL_CONFIG_H
51#include "nbtool_config.h" 51#include "nbtool_config.h"
52#endif 52#endif
53 53
54#include <sys/cdefs.h> 54#include <sys/cdefs.h>
55__KERNEL_RCSID(0, "$NetBSD: msdosfs_fat.c,v 1.32 2018/01/27 03:54:01 sevan Exp $"); 55__KERNEL_RCSID(0, "$NetBSD: msdosfs_fat.c,v 1.33 2018/07/25 22:07:59 kamil Exp $");
56 56
57/* 57/*
58 * kernel include files. 58 * kernel include files.
59 */ 59 */
60#include <sys/param.h> 60#include <sys/param.h>
61#include <sys/file.h> 61#include <sys/file.h>
62#ifdef _KERNEL 62#ifdef _KERNEL
63#include <sys/mount.h> /* to define statvfs structure */ 63#include <sys/mount.h> /* to define statvfs structure */
64#include <sys/errno.h> 64#include <sys/errno.h>
65#include <sys/systm.h> 65#include <sys/systm.h>
66#include <sys/kauth.h> 66#include <sys/kauth.h>
67#include <sys/dirent.h> 67#include <sys/dirent.h>
68#include <sys/namei.h> 68#include <sys/namei.h>
@@ -399,27 +399,27 @@ updatefats(struct msdosfsmount *pmp, str @@ -399,27 +399,27 @@ updatefats(struct msdosfsmount *pmp, str
399 int i, error; 399 int i, error;
400 struct buf *bpn; 400 struct buf *bpn;
401 401
402 DPRINTF(("%s(pmp %p, bp %p, fatbn %lu)\n", __func__, pmp, bp, fatbn)); 402 DPRINTF(("%s(pmp %p, bp %p, fatbn %lu)\n", __func__, pmp, bp, fatbn));
403 403
404 /* 404 /*
405 * If we have an FSInfo block, update it. 405 * If we have an FSInfo block, update it.
406 */ 406 */
407 if (pmp->pm_fsinfo) { 407 if (pmp->pm_fsinfo) {
408 u_long cn = pmp->pm_nxtfree; 408 u_long cn = pmp->pm_nxtfree;
409 409
410 if (pmp->pm_freeclustercount 410 if (pmp->pm_freeclustercount
411 && (pmp->pm_inusemap[cn / N_INUSEBITS] 411 && (pmp->pm_inusemap[cn / N_INUSEBITS]
412 & (1 << (cn % N_INUSEBITS)))) { 412 & (1U << (cn % N_INUSEBITS)))) {
413 /* 413 /*
414 * The cluster indicated in FSInfo isn't free 414 * The cluster indicated in FSInfo isn't free
415 * any longer. Got get a new free one. 415 * any longer. Got get a new free one.
416 */ 416 */
417 for (cn = 0; cn < pmp->pm_maxcluster; cn++) 417 for (cn = 0; cn < pmp->pm_maxcluster; cn++)
418 if (pmp->pm_inusemap[cn / N_INUSEBITS] != (u_int)-1) 418 if (pmp->pm_inusemap[cn / N_INUSEBITS] != (u_int)-1)
419 break; 419 break;
420 pmp->pm_nxtfree = cn 420 pmp->pm_nxtfree = cn
421 + ffs(pmp->pm_inusemap[cn / N_INUSEBITS] 421 + ffs(pmp->pm_inusemap[cn / N_INUSEBITS]
422 ^ (u_int)-1) - 1; 422 ^ (u_int)-1) - 1;
423 } 423 }
424 /* 424 /*
425 * XXX If the fsinfo block is stored on media with 425 * XXX If the fsinfo block is stored on media with
@@ -499,36 +499,36 @@ updatefats(struct msdosfsmount *pmp, str @@ -499,36 +499,36 @@ updatefats(struct msdosfsmount *pmp, str
499 * 499 *
500 * +----+----+----+ +----+----+----+ 500 * +----+----+----+ +----+----+----+
501 * | 3 0 1 | | 4 5 2 | 501 * | 3 0 1 | | 4 5 2 |
502 * +----+----+----+ +----+----+----+ 502 * +----+----+----+ +----+----+----+
503 * cluster n cluster n+1 503 * cluster n cluster n+1
504 * 504 *
505 * Where n is even. m = n + (n >> 2) 505 * Where n is even. m = n + (n >> 2)
506 * 506 *
507 */ 507 */
508static inline void 508static inline void
509usemap_alloc(struct msdosfsmount *pmp, u_long cn) 509usemap_alloc(struct msdosfsmount *pmp, u_long cn)
510{ 510{
511 511
512 pmp->pm_inusemap[cn / N_INUSEBITS] |= 1 << (cn % N_INUSEBITS); 512 pmp->pm_inusemap[cn / N_INUSEBITS] |= 1U << (cn % N_INUSEBITS);
513 pmp->pm_freeclustercount--; 513 pmp->pm_freeclustercount--;
514} 514}
515 515
516static inline void 516static inline void
517usemap_free(struct msdosfsmount *pmp, u_long cn) 517usemap_free(struct msdosfsmount *pmp, u_long cn)
518{ 518{
519 519
520 pmp->pm_freeclustercount++; 520 pmp->pm_freeclustercount++;
521 pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1 << (cn % N_INUSEBITS)); 521 pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1U << (cn % N_INUSEBITS));
522} 522}
523 523
524int 524int
525clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp) 525clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp)
526{ 526{
527 int error; 527 int error;
528 u_long oldcn; 528 u_long oldcn;
529 529
530 usemap_free(pmp, cluster); 530 usemap_free(pmp, cluster);
531 error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE); 531 error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
532 if (error) { 532 if (error) {
533 usemap_alloc(pmp, cluster); 533 usemap_alloc(pmp, cluster);
534 return (error); 534 return (error);
@@ -731,27 +731,27 @@ fatchain(struct msdosfsmount *pmp, u_lon @@ -731,27 +731,27 @@ fatchain(struct msdosfsmount *pmp, u_lon
731 * count - maximum interesting length 731 * count - maximum interesting length
732 */ 732 */
733int 733int
734chainlength(struct msdosfsmount *pmp, u_long start, u_long count) 734chainlength(struct msdosfsmount *pmp, u_long start, u_long count)
735{ 735{
736 u_long idx, max_idx; 736 u_long idx, max_idx;
737 u_int map; 737 u_int map;
738 u_long len; 738 u_long len;
739 739
740 max_idx = pmp->pm_maxcluster / N_INUSEBITS; 740 max_idx = pmp->pm_maxcluster / N_INUSEBITS;
741 idx = start / N_INUSEBITS; 741 idx = start / N_INUSEBITS;
742 start %= N_INUSEBITS; 742 start %= N_INUSEBITS;
743 map = pmp->pm_inusemap[idx]; 743 map = pmp->pm_inusemap[idx];
744 map &= ~((1 << start) - 1); 744 map &= ~((1U << start) - 1);
745 if (map) { 745 if (map) {
746 len = ffs(map) - 1 - start; 746 len = ffs(map) - 1 - start;
747 return (len > count ? count : len); 747 return (len > count ? count : len);
748 } 748 }
749 len = N_INUSEBITS - start; 749 len = N_INUSEBITS - start;
750 if (len >= count) 750 if (len >= count)
751 return (count); 751 return (count);
752 while (++idx <= max_idx) { 752 while (++idx <= max_idx) {
753 if (len >= count) 753 if (len >= count)
754 break; 754 break;
755 if ((map = pmp->pm_inusemap[idx]) != 0) { 755 if ((map = pmp->pm_inusemap[idx]) != 0) {
756 len += ffs(map) - 1; 756 len += ffs(map) - 1;
757 break; 757 break;
@@ -827,44 +827,44 @@ clusteralloc(struct msdosfsmount *pmp, u @@ -827,44 +827,44 @@ clusteralloc(struct msdosfsmount *pmp, u
827 len = 0; 827 len = 0;
828 } 828 }
829 829
830 /* 830 /*
831 * Start at a (pseudo) random place to maximize cluster runs 831 * Start at a (pseudo) random place to maximize cluster runs
832 * under multiple writers. 832 * under multiple writers.
833 */ 833 */
834 newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1); 834 newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
835 foundl = 0; 835 foundl = 0;
836 836
837 for (cn = newst; cn <= pmp->pm_maxcluster;) { 837 for (cn = newst; cn <= pmp->pm_maxcluster;) {
838 idx = cn / N_INUSEBITS; 838 idx = cn / N_INUSEBITS;
839 map = pmp->pm_inusemap[idx]; 839 map = pmp->pm_inusemap[idx];
840 map |= (1 << (cn % N_INUSEBITS)) - 1; 840 map |= (1U << (cn % N_INUSEBITS)) - 1;
841 if (map != (u_int)-1) { 841 if (map != (u_int)-1) {
842 cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1; 842 cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
843 if ((l = chainlength(pmp, cn, count)) >= count) 843 if ((l = chainlength(pmp, cn, count)) >= count)
844 return (chainalloc(pmp, cn, count, fillwith, retcluster, got)); 844 return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
845 if (l > foundl) { 845 if (l > foundl) {
846 foundcn = cn; 846 foundcn = cn;
847 foundl = l; 847 foundl = l;
848 } 848 }
849 cn += l + 1; 849 cn += l + 1;
850 continue; 850 continue;
851 } 851 }
852 cn += N_INUSEBITS - cn % N_INUSEBITS; 852 cn += N_INUSEBITS - cn % N_INUSEBITS;
853 } 853 }
854 for (cn = 0; cn < newst;) { 854 for (cn = 0; cn < newst;) {
855 idx = cn / N_INUSEBITS; 855 idx = cn / N_INUSEBITS;
856 map = pmp->pm_inusemap[idx]; 856 map = pmp->pm_inusemap[idx];
857 map |= (1 << (cn % N_INUSEBITS)) - 1; 857 map |= (1U << (cn % N_INUSEBITS)) - 1;
858 if (map != (u_int)-1) { 858 if (map != (u_int)-1) {
859 cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1; 859 cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
860 if ((l = chainlength(pmp, cn, count)) >= count) 860 if ((l = chainlength(pmp, cn, count)) >= count)
861 return (chainalloc(pmp, cn, count, fillwith, retcluster, got)); 861 return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
862 if (l > foundl) { 862 if (l > foundl) {
863 foundcn = cn; 863 foundcn = cn;
864 foundl = l; 864 foundl = l;
865 } 865 }
866 cn += l + 1; 866 cn += l + 1;
867 continue; 867 continue;
868 } 868 }
869 cn += N_INUSEBITS - cn % N_INUSEBITS; 869 cn += N_INUSEBITS - cn % N_INUSEBITS;
870 } 870 }