1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "firmware_handler.hpp"
18 
19 #include "data.hpp"
20 #include "flags.hpp"
21 #include "image_handler.hpp"
22 #include "status.hpp"
23 #include "util.hpp"
24 
25 #include <blobs-ipmid/blobs.hpp>
26 
27 #include <algorithm>
28 #include <cstdint>
29 #include <cstring>
30 #include <fstream>
31 #include <memory>
32 #include <string>
33 #include <vector>
34 
35 namespace ipmi_flash
36 {
37 
38 std::unique_ptr<blobs::GenericBlobInterface>
39     FirmwareBlobHandler::CreateFirmwareBlobHandler(
40         std::vector<HandlerPack>&& firmwares,
41         std::vector<DataHandlerPack>&& transports, ActionMap&& actionPacks)
42 {
43     /* There must be at least one in addition to the hash blob handler. */
44     if (firmwares.size() < 2)
45     {
46         std::fprintf(stderr, "Must provide at least two firmware handlers.");
47         return nullptr;
48     }
49     if (transports.empty())
50     {
51         return nullptr;
52     }
53     if (actionPacks.empty())
54     {
55         return nullptr;
56     }
57 
58     std::vector<std::string> blobs;
59     for (const auto& item : firmwares)
60     {
61         blobs.push_back(item.blobName);
62     }
63 
64     if (0 == std::count(blobs.begin(), blobs.end(), hashBlobId))
65     {
66         return nullptr;
67     }
68 
69     return std::make_unique<FirmwareBlobHandler>(std::move(firmwares), blobs,
70                                                  std::move(transports),
71                                                  std::move(actionPacks));
72 }
73 
74 /* Check if the path is in our supported list (or active list). */
75 bool FirmwareBlobHandler::canHandleBlob(const std::string& path)
76 {
77     return (std::count(blobIDs.begin(), blobIDs.end(), path) > 0);
78 }
79 
80 /*
81  * Grab the list of supported firmware.
82  *
83  * If there's an open firmware session, it'll already be present in the
84  * list as "/flash/active/image", and if the hash has started,
85  * "/flash/active/hash" regardless of mechanism.  This is done in the open
86  * comamnd, no extra work is required here.
87  */
88 std::vector<std::string> FirmwareBlobHandler::getBlobIds()
89 {
90     return blobIDs;
91 }
92 
93 /*
94  * Per the design, this mean abort, and this will trigger whatever
95  * appropriate actions are required to abort the process.
96  */
97 bool FirmwareBlobHandler::deleteBlob(const std::string& path)
98 {
99     switch (state)
100     {
101         case UpdateState::notYetStarted:
102             /* Trying to delete anything at this point has no effect and returns
103              * false.
104              */
105             return false;
106         case UpdateState::verificationPending:
107             abortProcess();
108             return true;
109         case UpdateState::updatePending:
110             abortProcess();
111             return true;
112         default:
113             break;
114     }
115 
116     return false;
117 }
118 
119 /*
120  * Stat on the files will return information such as what supported
121  * transport mechanisms are available.
122  *
123  * Stat on an active file or hash will return information such as the size
124  * of the data cached, and any additional pertinent information.  The
125  * blob_state on the active files will return the state of the update.
126  */
127 bool FirmwareBlobHandler::stat(const std::string& path, blobs::BlobMeta* meta)
128 {
129     /* We know we support this path because canHandle is called ahead */
130     if (path == verifyBlobId || path == activeImageBlobId ||
131         path == activeHashBlobId || path == updateBlobId)
132     {
133         /* These blobs are placeholders that indicate things, or allow actions,
134          * but are not stat-able as-is.
135          */
136         return false;
137     }
138 
139     /* They are requesting information about the generic blob_id. */
140 
141     /* Older host tools expect the blobState to contain a bitmask of available
142      * transport backends, so report that we support all of them in order to
143      * preserve backwards compatibility.
144      */
145     meta->blobState = transportMask;
146     meta->size = 0;
147     return true;
148 }
149 
150 ActionStatus FirmwareBlobHandler::getActionStatus()
151 {
152     ActionStatus value = ActionStatus::unknown;
153     auto* pack = getActionPack();
154 
155     switch (state)
156     {
157         case UpdateState::verificationPending:
158             value = ActionStatus::unknown;
159             break;
160         case UpdateState::verificationStarted:
161             /* If we got here, there must be data AND a hash, not just a hash,
162              * therefore pack will be known. */
163             if (!pack)
164             {
165                 break;
166             }
167             value = pack->verification->status();
168             lastVerificationStatus = value;
169             break;
170         case UpdateState::verificationCompleted:
171             value = lastVerificationStatus;
172             break;
173         case UpdateState::updatePending:
174             value = ActionStatus::unknown;
175             break;
176         case UpdateState::updateStarted:
177             if (!pack)
178             {
179                 break;
180             }
181             value = pack->update->status();
182             lastUpdateStatus = value;
183             break;
184         case UpdateState::updateCompleted:
185             value = lastUpdateStatus;
186             break;
187         default:
188             break;
189     }
190 
191     return value;
192 }
193 
194 /*
195  * Return stat information on an open session.  It therefore must be an active
196  * handle to either the active image or active hash.
197  */
198 bool FirmwareBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
199 {
200     auto item = lookup.find(session);
201     if (item == lookup.end())
202     {
203         return false;
204     }
205 
206     /* The size here refers to the size of the file -- of something analagous.
207      */
208     meta->size = (item->second->imageHandler)
209                      ? item->second->imageHandler->getSize()
210                      : 0;
211 
212     meta->metadata.clear();
213 
214     if (item->second->activePath == verifyBlobId ||
215         item->second->activePath == updateBlobId)
216     {
217         ActionStatus value = getActionStatus();
218 
219         meta->metadata.push_back(static_cast<std::uint8_t>(value));
220 
221         /* Change the firmware handler's state and the blob's stat value
222          * depending.
223          */
224         if (value == ActionStatus::success || value == ActionStatus::failed)
225         {
226             if (item->second->activePath == verifyBlobId)
227             {
228                 changeState(UpdateState::verificationCompleted);
229             }
230             else
231             {
232                 /* item->second->activePath == updateBlobId */
233                 changeState(UpdateState::updateCompleted);
234             }
235 
236             item->second->flags &= ~blobs::StateFlags::committing;
237 
238             if (value == ActionStatus::success)
239             {
240                 item->second->flags |= blobs::StateFlags::committed;
241             }
242             else
243             {
244                 item->second->flags |= blobs::StateFlags::commit_error;
245             }
246         }
247     }
248 
249     /* The blobState here relates to an active sesion, so we should return the
250      * flags used to open this session.
251      */
252     meta->blobState = item->second->flags;
253 
254     /* The metadata blob returned comes from the data handler... it's used for
255      * instance, in P2A bridging to get required information about the mapping,
256      * and is the "opposite" of the lpc writemeta requirement.
257      */
258     if (item->second->dataHandler)
259     {
260         auto bytes = item->second->dataHandler->readMeta();
261         meta->metadata.insert(meta->metadata.begin(), bytes.begin(),
262                               bytes.end());
263     }
264 
265     return true;
266 }
267 
268 /*
269  * If you open /flash/image or /flash/tarball, or /flash/hash it will
270  * interpret the open flags and perform whatever actions are required for
271  * that update process.  The session returned can be used immediately for
272  * sending data down, without requiring one to open the new active file.
273  *
274  * If you open the active flash image or active hash it will let you
275  * overwrite pieces, depending on the state.
276  *
277  * Once the verification process has started the active files cannot be
278  * opened.
279  *
280  * You can only have one open session at a time.  Which means, you can only
281  * have one file open at a time.  Trying to open the hash blob_id while you
282  * still have the flash image blob_id open will fail.  Opening the flash
283  * blob_id when it is already open will fail.
284  */
285 bool FirmwareBlobHandler::open(uint16_t session, uint16_t flags,
286                                const std::string& path)
287 {
288     /* Is there an open session already? We only allow one at a time.
289      *
290      * Further on this, if there's an active session to the hash we don't allow
291      * re-opening the image, and if we have the image open, we don't allow
292      * opening the hash.  This design decision may be re-evaluated, and changed
293      * to only allow one session per object type (of the two types).  But,
294      * consider if the hash is open, do we want to allow writing to the image?
295      * And why would we?  But, really, the point of no-return is once the
296      * verification process has begun -- which is done via commit() on the hash
297      * blob_id, we no longer want to allow updating the contents.
298      */
299     if (fileOpen())
300     {
301         return false;
302     }
303 
304     /* The active blobs are only meant to indicate status that something has
305      * opened the image file or the hash file.
306      */
307     if (path == activeImageBlobId || path == activeHashBlobId)
308     {
309         /* 2a) are they opening the active image? this can only happen if they
310          * already started one (due to canHandleBlob's behavior).
311          */
312         /* 2b) are they opening the active hash? this can only happen if they
313          * already started one (due to canHandleBlob's behavior).
314          */
315         return false;
316     }
317 
318     /* Check that they've opened for writing - read back not currently
319      * supported.
320      */
321     if ((flags & blobs::OpenFlags::write) == 0)
322     {
323         return false;
324     }
325 
326     /* Because canHandleBlob is called before open, we know that if they try to
327      *  open the verifyBlobId, they're in a state where it's present.
328      */
329 
330     switch (state)
331     {
332         case UpdateState::notYetStarted:
333             /* Only hashBlobId and firmware BlobIds present. */
334             break;
335         case UpdateState::uploadInProgress:
336             /* Unreachable code because if it's started a file is open. */
337             break;
338         case UpdateState::verificationPending:
339             /* Handle opening the verifyBlobId --> we know the image and hash
340              * aren't open because of the fileOpen() check. They can still open
341              * other files from this state to transition back into
342              * uploadInProgress.
343              *
344              * The file must be opened for writing, but no transport mechanism
345              * specified since it's irrelevant.
346              */
347             if (path == verifyBlobId)
348             {
349                 verifyImage.flags = flags;
350 
351                 lookup[session] = &verifyImage;
352 
353                 return true;
354             }
355             break;
356         case UpdateState::verificationStarted:
357         case UpdateState::verificationCompleted:
358             /* Unreachable code because if it's started a file is open. */
359             return false;
360         case UpdateState::updatePending:
361         {
362             /* When in this state, they can only open the updateBlobId */
363             if (path == updateBlobId)
364             {
365                 updateImage.flags = flags;
366 
367                 lookup[session] = &updateImage;
368 
369                 return true;
370             }
371             else
372             {
373                 return false;
374             }
375         }
376         case UpdateState::updateStarted:
377         case UpdateState::updateCompleted:
378             /* Unreachable code because if it's started a file is open. */
379             break;
380         default:
381             break;
382     }
383 
384     /* To support multiple firmware options, we need to make sure they're
385      * opening the one they already opened during this update sequence, or it's
386      * the first time they're opening it.
387      */
388     if (path != hashBlobId)
389     {
390         /* If they're not opening the hashBlobId they must be opening a firmware
391          * handler.
392          */
393         if (openedFirmwareType.empty())
394         {
395             /* First time for this sequence. */
396             openedFirmwareType = path;
397         }
398         else
399         {
400             if (openedFirmwareType != path)
401             {
402                 /* Previously, in this sequence they opened /flash/image, and
403                  * now they're opening /flash/bios without finishing out
404                  * /flash/image (for example).
405                  */
406                 std::fprintf(stderr, "Trying to open alternate firmware while "
407                                      "unfinished with other firmware.\n");
408                 return false;
409             }
410         }
411     }
412 
413     /* There are two abstractions at play, how you get the data and how you
414      * handle that data. such that, whether the data comes from the PCI bridge
415      * or LPC bridge is not connected to whether the data goes into a static
416      * layout flash update or a UBI tarball.
417      */
418 
419     std::uint16_t transportFlag = flags & transportMask;
420 
421     /* How are they expecting to copy this data? */
422     auto d = std::find_if(transports.begin(), transports.end(),
423                           [&transportFlag](const auto& iter) {
424                               return (iter.bitmask == transportFlag);
425                           });
426     if (d == transports.end())
427     {
428         return false;
429     }
430 
431     /* We found the transport handler they requested */
432 
433     /* Elsewhere I do this check by checking "if ::ipmi" because that's the
434      * only non-external data pathway -- but this is just a more generic
435      * approach to that.
436      */
437     if (d->handler)
438     {
439         /* If the data handler open call fails, open fails. */
440         if (!d->handler->open())
441         {
442             return false;
443         }
444     }
445 
446     /* Do we have a file handler for the type of file they're opening.
447      * Note: This should only fail if something is somehow crazy wrong.
448      * Since the canHandle() said yes, and that's tied into the list of explicit
449      * firmware handers (and file handlers, like this'll know where to write the
450      * tarball, etc).
451      */
452     auto h = std::find_if(
453         handlers.begin(), handlers.end(),
454         [&path](const auto& iter) { return (iter.blobName == path); });
455     if (h == handlers.end())
456     {
457         return false;
458     }
459 
460     /* Ok, so we found a handler that matched, so call open() */
461     if (!h->handler->open(path, std::ios::out))
462     {
463         return false;
464     }
465 
466     Session* curr;
467     const char* active;
468 
469     if (path == hashBlobId)
470     {
471         /* 2c) are they opening the /flash/hash ? (to start the process) */
472         curr = &activeHash;
473         active = activeHashBlobId;
474     }
475     else
476     {
477         curr = &activeImage;
478         active = activeImageBlobId;
479     }
480 
481     curr->flags = flags;
482     curr->dataHandler = d->handler.get();
483     curr->imageHandler = h->handler.get();
484 
485     lookup[session] = curr;
486 
487     addBlobId(active);
488     removeBlobId(verifyBlobId);
489 
490     changeState(UpdateState::uploadInProgress);
491 
492     return true;
493 }
494 
495 /**
496  * The write command really just grabs the data from wherever it is and sends it
497  * to the image handler.  It's the image handler's responsibility to deal with
498  * the data provided.
499  *
500  * This receives a session from the blob manager, therefore it is always called
501  * between open() and close().
502  */
503 bool FirmwareBlobHandler::write(uint16_t session, uint32_t offset,
504                                 const std::vector<uint8_t>& data)
505 {
506     auto item = lookup.find(session);
507     if (item == lookup.end())
508     {
509         return false;
510     }
511 
512     /* Prevent writing during verification. */
513     if (state == UpdateState::verificationStarted)
514     {
515         return false;
516     }
517 
518     /* Prevent writing to the verification or update blobs. */
519     if (item->second->activePath == verifyBlobId ||
520         item->second->activePath == updateBlobId)
521     {
522         return false;
523     }
524 
525     std::vector<std::uint8_t> bytes;
526 
527     if (item->second->flags & FirmwareFlags::UpdateFlags::ipmi)
528     {
529         bytes = data;
530     }
531     else
532     {
533         /* little endian required per design, and so on, but TODO: do endianness
534          * with boost.
535          */
536         struct ExtChunkHdr header;
537 
538         if (data.size() != sizeof(header))
539         {
540             return false;
541         }
542 
543         std::memcpy(&header, data.data(), data.size());
544         bytes = item->second->dataHandler->copyFrom(header.length);
545     }
546 
547     return item->second->imageHandler->write(offset, bytes);
548 }
549 
550 /*
551  * If the active session (image or hash) is over LPC, this allows
552  * configuring it.  This option is only available before you start
553  * writing data for the given item (image or hash).  This will return
554  * false at any other part. -- the lpc handler portion will know to return
555  * false.
556  */
557 bool FirmwareBlobHandler::writeMeta(uint16_t session, uint32_t offset,
558                                     const std::vector<uint8_t>& data)
559 {
560     auto item = lookup.find(session);
561     if (item == lookup.end())
562     {
563         return false;
564     }
565 
566     if (item->second->flags & FirmwareFlags::UpdateFlags::ipmi)
567     {
568         return false;
569     }
570 
571     /* Prevent writing meta to the verification blob (it has no data handler).
572      */
573     if (item->second->dataHandler)
574     {
575         return item->second->dataHandler->writeMeta(data);
576     }
577 
578     return false;
579 }
580 
581 /*
582  * If this command is called on the session for the verifyBlobId, it'll
583  * trigger a systemd service `verify_image.service` to attempt to verify
584  * the image.
585  *
586  * For this file to have opened, the other two must be closed, which means any
587  * out-of-band transport mechanism involved is closed.
588  */
589 bool FirmwareBlobHandler::commit(uint16_t session,
590                                  const std::vector<uint8_t>& data)
591 {
592     auto item = lookup.find(session);
593     if (item == lookup.end())
594     {
595         return false;
596     }
597 
598     /* You can only commit on the verifyBlodId or updateBlobId */
599     if (item->second->activePath != verifyBlobId &&
600         item->second->activePath != updateBlobId)
601     {
602         std::fprintf(stderr, "path: '%s' not expected for commit\n",
603                      item->second->activePath.c_str());
604         return false;
605     }
606 
607     switch (state)
608     {
609         case UpdateState::verificationPending:
610             /* Set state to committing. */
611             item->second->flags |= blobs::StateFlags::committing;
612             return triggerVerification();
613         case UpdateState::verificationStarted:
614             /* Calling repeatedly has no effect within an update process. */
615             return true;
616         case UpdateState::verificationCompleted:
617             /* Calling after the verification process has completed returns
618              * failure. */
619             return false;
620         case UpdateState::updatePending:
621             item->second->flags |= blobs::StateFlags::committing;
622             return triggerUpdate();
623         case UpdateState::updateStarted:
624             /* Calling repeatedly has no effect within an update process. */
625             return true;
626         default:
627             return false;
628     }
629 }
630 
631 /*
632  * Close must be called on the firmware image before triggering
633  * verification via commit. Once the verification is complete, you can
634  * then close the hash file.
635  *
636  * If the `verify_image.service` returned success, closing the hash file
637  * will have a specific behavior depending on the update. If it's UBI,
638  * it'll perform the install. If it's static layout, it'll do nothing. The
639  * verify_image service in the static layout case is responsible for placing
640  * the file in the correct staging position.
641  */
642 bool FirmwareBlobHandler::close(uint16_t session)
643 {
644     auto item = lookup.find(session);
645     if (item == lookup.end())
646     {
647         return false;
648     }
649 
650     switch (state)
651     {
652         case UpdateState::uploadInProgress:
653             /* They are closing a data pathway (image, tarball, hash). */
654             changeState(UpdateState::verificationPending);
655 
656             /* Add verify blob ID now that we can expect it, IIF they also wrote
657              * some data.
658              */
659             if (std::count(blobIDs.begin(), blobIDs.end(), activeImageBlobId))
660             {
661                 addBlobId(verifyBlobId);
662             }
663             break;
664         case UpdateState::verificationPending:
665             /* They haven't triggered, therefore closing is uninteresting.
666              */
667             break;
668         case UpdateState::verificationStarted:
669             /* Abort without checking to see if it happened to finish. Require
670              * the caller to stat() deliberately.
671              */
672             abortVerification();
673             abortProcess();
674             break;
675         case UpdateState::verificationCompleted:
676             if (lastVerificationStatus == ActionStatus::success)
677             {
678                 changeState(UpdateState::updatePending);
679                 addBlobId(updateBlobId);
680                 removeBlobId(verifyBlobId);
681             }
682             else
683             {
684                 /* Verification failed, and the host-tool knows this by calling
685                  * stat(), which triggered the state change to
686                  * verificationCompleted.
687                  *
688                  * Therefore, let's abort the process at this point.
689                  */
690                 abortProcess();
691             }
692             break;
693         case UpdateState::updatePending:
694             /* They haven't triggered the update, therefore this is
695              * uninteresting. */
696             break;
697         case UpdateState::updateStarted:
698             /* Abort without checking to see if it happened to finish. Require
699              * the caller to stat() deliberately.
700              */
701             abortUpdate();
702             abortProcess();
703             break;
704         case UpdateState::updateCompleted:
705             if (lastUpdateStatus == ActionStatus::failed)
706             {
707                 /* TODO: lOG something? */
708                 std::fprintf(stderr, "Update failed\n");
709             }
710 
711             abortProcess();
712             break;
713         default:
714             break;
715     }
716 
717     if (!lookup.empty())
718     {
719         if (item->second->dataHandler)
720         {
721             item->second->dataHandler->close();
722         }
723         if (item->second->imageHandler)
724         {
725             item->second->imageHandler->close();
726         }
727         lookup.erase(item);
728     }
729     return true;
730 }
731 
732 void FirmwareBlobHandler::changeState(UpdateState next)
733 {
734     state = next;
735 
736     if (state == UpdateState::notYetStarted)
737     {
738         /* Going back to notyetstarted, let them trigger preparation again. */
739         preparationTriggered = false;
740     }
741     else if (state == UpdateState::uploadInProgress)
742     {
743         /* Store this transition logic here instead of ::open() */
744         if (!preparationTriggered)
745         {
746             auto* pack = getActionPack();
747             if (pack)
748             {
749                 pack->preparation->trigger();
750                 preparationTriggered = true;
751             }
752         }
753     }
754 }
755 
756 bool FirmwareBlobHandler::expire(uint16_t session)
757 {
758     abortProcess();
759     return true;
760 }
761 
762 /*
763  * Currently, the design does not provide this with a function, however,
764  * it will likely change to support reading data back.
765  */
766 std::vector<uint8_t> FirmwareBlobHandler::read(uint16_t session,
767                                                uint32_t offset,
768                                                uint32_t requestedSize)
769 {
770     return {};
771 }
772 
773 void FirmwareBlobHandler::abortProcess()
774 {
775     /* Closing of open files is handled from close() -- Reaching here from
776      * delete may never be supported.
777      */
778     removeBlobId(verifyBlobId);
779     removeBlobId(updateBlobId);
780     removeBlobId(activeImageBlobId);
781     removeBlobId(activeHashBlobId);
782 
783     for (auto item : lookup)
784     {
785         if (item.second->dataHandler)
786         {
787             item.second->dataHandler->close();
788         }
789         if (item.second->imageHandler)
790         {
791             item.second->imageHandler->close();
792         }
793     }
794     lookup.clear();
795 
796     openedFirmwareType = "";
797     changeState(UpdateState::notYetStarted);
798 }
799 
800 void FirmwareBlobHandler::abortVerification()
801 {
802     auto* pack = getActionPack();
803     if (pack)
804     {
805         pack->verification->abort();
806     }
807 }
808 
809 bool FirmwareBlobHandler::triggerVerification()
810 {
811     auto* pack = getActionPack();
812     if (!pack)
813     {
814         return false;
815     }
816 
817     bool result = pack->verification->trigger();
818     if (result)
819     {
820         changeState(UpdateState::verificationStarted);
821     }
822 
823     return result;
824 }
825 
826 void FirmwareBlobHandler::abortUpdate()
827 {
828     auto* pack = getActionPack();
829     if (pack)
830     {
831         pack->update->abort();
832     }
833 }
834 
835 bool FirmwareBlobHandler::triggerUpdate()
836 {
837     auto* pack = getActionPack();
838     if (!pack)
839     {
840         return false;
841     }
842 
843     bool result = pack->update->trigger();
844     if (result)
845     {
846         changeState(UpdateState::updateStarted);
847     }
848 
849     return result;
850 }
851 
852 } // namespace ipmi_flash
853