Skip to content

Commit e1d8ccb

Browse files
xmine64binarymaster
authored andcommitted
[USER32] Fix LookupIconIdFromDirectoryEx crash with invalid pointer (reactos#9263)
This problem is similar to 6085191 (reactos#5106) / CORE-15879. Add SEH exception handler to prevent the crash, matching Windows behavior. CORE-19544
1 parent 39c9f57 commit e1d8ccb

1 file changed

Lines changed: 131 additions & 121 deletions

File tree

‎win32ss/user/user32/windows/cursoricon.c‎

Lines changed: 131 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -2623,140 +2623,150 @@ int WINAPI LookupIconIdFromDirectoryEx(
26232623

26242624
TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags);
26252625

2626-
if(!(dir && !dir->idReserved && (dir->idType & 3)))
2626+
/* Wrap the whole implementation in SEH in order to gracefully handle
2627+
* any PE resource corruption case in a simple way. */
2628+
_SEH2_TRY
26272629
{
2628-
WARN("Invalid resource.\n");
2629-
return 0;
2630-
}
2630+
if(!(dir && !dir->idReserved && (dir->idType & 3)))
2631+
{
2632+
WARN("Invalid resource.\n");
2633+
_SEH2_YIELD(return 0);
2634+
}
26312635

2632-
if(Flags & LR_MONOCHROME)
2633-
bppDesired = 1;
2634-
else
2635-
{
2636-
HDC icScreen;
2637-
icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL);
2638-
if(!icScreen)
2639-
return FALSE;
2636+
if(Flags & LR_MONOCHROME)
2637+
bppDesired = 1;
2638+
else
2639+
{
2640+
HDC icScreen;
2641+
icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL);
2642+
if(!icScreen)
2643+
_SEH2_YIELD(return 0);
2644+
2645+
bppDesired = GetDeviceCaps(icScreen, BITSPIXEL);
2646+
DeleteDC(icScreen);
2647+
}
2648+
2649+
if(!cxDesired)
2650+
cxDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR) : 256;
2651+
if(!cyDesired)
2652+
cyDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR) : 256;
2653+
2654+
/* Find the best match for the desired size */
2655+
for(i = 0; i < dir->idCount; i++)
2656+
{
2657+
entry = &dir->idEntries[i];
2658+
width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2659+
/* Height is twice as big in cursor resources */
2660+
height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2661+
/* 0 represents 256 */
2662+
if(!width) width = 256;
2663+
if(!height) height = 256;
2664+
/* Calculate the "score" (lower is better) */
2665+
score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2666+
if( score > bestScore)
2667+
continue;
2668+
/* Bigger than requested lowers the score */
2669+
if(width > cxDesired)
2670+
score -= width - cxDesired;
2671+
if(height > cyDesired)
2672+
score -= height - cyDesired;
2673+
if(score > bestScore)
2674+
continue;
2675+
if(score == bestScore)
2676+
{
2677+
if(entry->wBitCount > BitCount)
2678+
BitCount = entry->wBitCount;
2679+
numMatch++;
2680+
continue;
2681+
}
2682+
iIndex = i;
2683+
numMatch = 1;
2684+
bestScore = score;
2685+
BitCount = entry->wBitCount;
2686+
}
26402687

2641-
bppDesired = GetDeviceCaps(icScreen, BITSPIXEL);
2642-
DeleteDC(icScreen);
2643-
}
2688+
if(numMatch == 1)
2689+
{
2690+
/* Only one entry fits the asked dimensions */
2691+
_SEH2_YIELD(return dir->idEntries[iIndex].wResId);
2692+
}
26442693

2645-
if(!cxDesired)
2646-
cxDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR) : 256;
2647-
if(!cyDesired)
2648-
cyDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR) : 256;
2694+
/* Avoid paletted icons on non-paletted device */
2695+
if (bppDesired > 8 && BitCount > 8)
2696+
notPaletted = TRUE;
26492697

2650-
/* Find the best match for the desired size */
2651-
for(i = 0; i < dir->idCount; i++)
2652-
{
2653-
entry = &dir->idEntries[i];
2654-
width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2655-
/* Height is twice as big in cursor resources */
2656-
height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2657-
/* 0 represents 256 */
2658-
if(!width) width = 256;
2659-
if(!height) height = 256;
2660-
/* Calculate the "score" (lower is better) */
2661-
score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2662-
if( score > bestScore)
2663-
continue;
2664-
/* Bigger than requested lowers the score */
2665-
if(width > cxDesired)
2666-
score -= width - cxDesired;
2667-
if(height > cyDesired)
2668-
score -= height - cyDesired;
2669-
if(score > bestScore)
2670-
continue;
2671-
if(score == bestScore)
2672-
{
2673-
if(entry->wBitCount > BitCount)
2698+
BitCount = 0;
2699+
iIndex = -1;
2700+
/* Now find the entry with the best depth */
2701+
for(i = 0; i < dir->idCount; i++)
2702+
{
2703+
entry = &dir->idEntries[i];
2704+
width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2705+
height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2706+
/* 0 represents 256 */
2707+
if(!width) width = 256;
2708+
if(!height) height = 256;
2709+
/* Check if this is the best match we had */
2710+
score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2711+
if(width > cxDesired)
2712+
score -= width - cxDesired;
2713+
if(height > cyDesired)
2714+
score -= height - cyDesired;
2715+
if(score != bestScore)
2716+
continue;
2717+
/* Exact match? */
2718+
if(entry->wBitCount == bppDesired)
2719+
_SEH2_YIELD(return entry->wResId);
2720+
/* We take the highest possible but smaller than the display depth */
2721+
if((entry->wBitCount > BitCount) && (entry->wBitCount < bppDesired))
2722+
{
2723+
/* Avoid paletted icons on non paletted devices */
2724+
if ((entry->wBitCount <= 8) && notPaletted)
2725+
continue;
2726+
iIndex = i;
26742727
BitCount = entry->wBitCount;
2675-
numMatch++;
2676-
continue;
2728+
}
26772729
}
2678-
iIndex = i;
2679-
numMatch = 1;
2680-
bestScore = score;
2681-
BitCount = entry->wBitCount;
2682-
}
26832730

2684-
if(numMatch == 1)
2685-
{
2686-
/* Only one entry fits the asked dimensions */
2687-
return dir->idEntries[iIndex].wResId;
2688-
}
2689-
2690-
/* Avoid paletted icons on non-paletted device */
2691-
if (bppDesired > 8 && BitCount > 8)
2692-
notPaletted = TRUE;
2693-
2694-
BitCount = 0;
2695-
iIndex = -1;
2696-
/* Now find the entry with the best depth */
2697-
for(i = 0; i < dir->idCount; i++)
2698-
{
2699-
entry = &dir->idEntries[i];
2700-
width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2701-
height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2702-
/* 0 represents 256 */
2703-
if(!width) width = 256;
2704-
if(!height) height = 256;
2705-
/* Check if this is the best match we had */
2706-
score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2707-
if(width > cxDesired)
2708-
score -= width - cxDesired;
2709-
if(height > cyDesired)
2710-
score -= height - cyDesired;
2711-
if(score != bestScore)
2712-
continue;
2713-
/* Exact match? */
2714-
if(entry->wBitCount == bppDesired)
2715-
return entry->wResId;
2716-
/* We take the highest possible but smaller than the display depth */
2717-
if((entry->wBitCount > BitCount) && (entry->wBitCount < bppDesired))
2718-
{
2719-
/* Avoid paletted icons on non paletted devices */
2720-
if ((entry->wBitCount <= 8) && notPaletted)
2731+
if(iIndex >= 0)
2732+
_SEH2_YIELD(return dir->idEntries[iIndex].wResId);
2733+
2734+
/* No inferior or equal depth available. Get the smallest bigger one */
2735+
BitCount = 0xFFFF;
2736+
iIndex = -1;
2737+
for(i = 0; i < dir->idCount; i++)
2738+
{
2739+
entry = &dir->idEntries[i];
2740+
width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2741+
height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2742+
/* 0 represents 256 */
2743+
if(!width) width = 256;
2744+
if(!height) height = 256;
2745+
/* Check if this is the best match we had */
2746+
score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2747+
if(width > cxDesired)
2748+
score -= width - cxDesired;
2749+
if(height > cyDesired)
2750+
score -= height - cyDesired;
2751+
if(score != bestScore)
27212752
continue;
2722-
iIndex = i;
2723-
BitCount = entry->wBitCount;
2753+
/* Check the bit depth */
2754+
if(entry->wBitCount < BitCount)
2755+
{
2756+
if((entry->wBitCount <= 8) && notPaletted)
2757+
continue;
2758+
iIndex = i;
2759+
BitCount = entry->wBitCount;
2760+
}
27242761
}
2762+
if (iIndex >= 0)
2763+
_SEH2_YIELD(return dir->idEntries[iIndex].wResId);
27252764
}
2726-
2727-
if(iIndex >= 0)
2728-
return dir->idEntries[iIndex].wResId;
2729-
2730-
/* No inferior or equal depth available. Get the smallest bigger one */
2731-
BitCount = 0xFFFF;
2732-
iIndex = -1;
2733-
for(i = 0; i < dir->idCount; i++)
2765+
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
27342766
{
2735-
entry = &dir->idEntries[i];
2736-
width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2737-
height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2738-
/* 0 represents 256 */
2739-
if(!width) width = 256;
2740-
if(!height) height = 256;
2741-
/* Check if this is the best match we had */
2742-
score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2743-
if(width > cxDesired)
2744-
score -= width - cxDesired;
2745-
if(height > cyDesired)
2746-
score -= height - cyDesired;
2747-
if(score != bestScore)
2748-
continue;
2749-
/* Check the bit depth */
2750-
if(entry->wBitCount < BitCount)
2751-
{
2752-
if((entry->wBitCount <= 8) && notPaletted)
2753-
continue;
2754-
iIndex = i;
2755-
BitCount = entry->wBitCount;
2756-
}
2767+
ERR("Invalid resource (0x%p)\n", presbits);
27572768
}
2758-
if (iIndex >= 0)
2759-
return dir->idEntries[iIndex].wResId;
2769+
_SEH2_END;
27602770

27612771
return 0;
27622772
}

0 commit comments

Comments
 (0)