]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Notify.c
MdeModulePkg: Fix use-after-free error in InstallConfigurationTable()
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Notify.c
1 /** @file
2 Support functions for UEFI protocol notification infrastructure.
3
4 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PiSmmCore.h"
16
17 /**
18 Signal event for every protocol in protocol entry.
19
20 @param Prot Protocol interface
21
22 **/
23 VOID
24 SmmNotifyProtocol (
25 IN PROTOCOL_INTERFACE *Prot
26 )
27 {
28 PROTOCOL_ENTRY *ProtEntry;
29 PROTOCOL_NOTIFY *ProtNotify;
30 LIST_ENTRY *Link;
31
32 ProtEntry = Prot->Protocol;
33 for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
34 ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
35 ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);
36 }
37 }
38
39 /**
40 Removes Protocol from the protocol list (but not the handle list).
41
42 @param Handle The handle to remove protocol on.
43 @param Protocol GUID of the protocol to be moved
44 @param Interface The interface of the protocol
45
46 @return Protocol Entry
47
48 **/
49 PROTOCOL_INTERFACE *
50 SmmRemoveInterfaceFromProtocol (
51 IN IHANDLE *Handle,
52 IN EFI_GUID *Protocol,
53 IN VOID *Interface
54 )
55 {
56 PROTOCOL_INTERFACE *Prot;
57 PROTOCOL_NOTIFY *ProtNotify;
58 PROTOCOL_ENTRY *ProtEntry;
59 LIST_ENTRY *Link;
60
61 Prot = SmmFindProtocolInterface (Handle, Protocol, Interface);
62 if (Prot != NULL) {
63
64 ProtEntry = Prot->Protocol;
65
66 //
67 // If there's a protocol notify location pointing to this entry, back it up one
68 //
69 for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
70 ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
71
72 if (ProtNotify->Position == &Prot->ByProtocol) {
73 ProtNotify->Position = Prot->ByProtocol.BackLink;
74 }
75 }
76
77 //
78 // Remove the protocol interface entry
79 //
80 RemoveEntryList (&Prot->ByProtocol);
81 }
82
83 return Prot;
84 }
85
86 /**
87 Add a new protocol notification record for the request protocol.
88
89 @param Protocol The requested protocol to add the notify
90 registration
91 @param Function Points to the notification function
92 @param Registration Returns the registration record
93
94 @retval EFI_SUCCESS Successfully returned the registration record
95 that has been added or unhooked
96 @retval EFI_INVALID_PARAMETER Protocol is NULL or Registration is NULL
97 @retval EFI_OUT_OF_RESOURCES Not enough memory resource to finish the request
98 @retval EFI_NOT_FOUND If the registration is not found when Function == NULL
99
100 **/
101 EFI_STATUS
102 EFIAPI
103 SmmRegisterProtocolNotify (
104 IN CONST EFI_GUID *Protocol,
105 IN EFI_SMM_NOTIFY_FN Function,
106 OUT VOID **Registration
107 )
108 {
109 PROTOCOL_ENTRY *ProtEntry;
110 PROTOCOL_NOTIFY *ProtNotify;
111 LIST_ENTRY *Link;
112 EFI_STATUS Status;
113
114 if (Protocol == NULL || Registration == NULL) {
115 return EFI_INVALID_PARAMETER;
116 }
117
118 if (Function == NULL) {
119 //
120 // Get the protocol entry per Protocol
121 //
122 ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE);
123 if (ProtEntry != NULL) {
124 ProtNotify = (PROTOCOL_NOTIFY * )*Registration;
125 for (Link = ProtEntry->Notify.ForwardLink;
126 Link != &ProtEntry->Notify;
127 Link = Link->ForwardLink) {
128 //
129 // Compare the notification record
130 //
131 if (ProtNotify == (CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))){
132 //
133 // If Registration is an existing registration, then unhook it
134 //
135 ProtNotify->Signature = 0;
136 RemoveEntryList (&ProtNotify->Link);
137 FreePool (ProtNotify);
138 return EFI_SUCCESS;
139 }
140 }
141 }
142 //
143 // If the registration is not found
144 //
145 return EFI_NOT_FOUND;
146 }
147
148 ProtNotify = NULL;
149
150 //
151 // Get the protocol entry to add the notification too
152 //
153 ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);
154 if (ProtEntry != NULL) {
155 //
156 // Find whether notification already exist
157 //
158 for (Link = ProtEntry->Notify.ForwardLink;
159 Link != &ProtEntry->Notify;
160 Link = Link->ForwardLink) {
161
162 ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
163 if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&
164 (ProtNotify->Function == Function)) {
165
166 //
167 // Notification already exist
168 //
169 *Registration = ProtNotify;
170
171 return EFI_SUCCESS;
172 }
173 }
174
175 //
176 // Allocate a new notification record
177 //
178 ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));
179 if (ProtNotify != NULL) {
180 ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
181 ProtNotify->Protocol = ProtEntry;
182 ProtNotify->Function = Function;
183 //
184 // Start at the ending
185 //
186 ProtNotify->Position = ProtEntry->Protocols.BackLink;
187
188 InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
189 }
190 }
191
192 //
193 // Done. If we have a protocol notify entry, then return it.
194 // Otherwise, we must have run out of resources trying to add one
195 //
196 Status = EFI_OUT_OF_RESOURCES;
197 if (ProtNotify != NULL) {
198 *Registration = ProtNotify;
199 Status = EFI_SUCCESS;
200 }
201 return Status;
202 }