Merge tag 'i3c/for-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
[platform/kernel/linux-rpi.git] / block / sed-opal.c
index 9bdb833..463873f 100644 (file)
@@ -2461,6 +2461,44 @@ static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
        return execute_steps(dev, mbrdone_step, ARRAY_SIZE(mbrdone_step));
 }
 
+static void opal_lock_check_for_saved_key(struct opal_dev *dev,
+                           struct opal_lock_unlock *lk_unlk)
+{
+       struct opal_suspend_data *iter;
+
+       if (lk_unlk->l_state != OPAL_LK ||
+                       lk_unlk->session.opal_key.key_len > 0)
+               return;
+
+       /*
+        * Usually when closing a crypto device (eg: dm-crypt with LUKS) the
+        * volume key is not required, as it requires root privileges anyway,
+        * and root can deny access to a disk in many ways regardless.
+        * Requiring the volume key to lock the device is a peculiarity of the
+        * OPAL specification. Given we might already have saved the key if
+        * the user requested it via the 'IOC_OPAL_SAVE' ioctl, we can use
+        * that key to lock the device if no key was provided here, the
+        * locking range matches and the appropriate flag was passed with
+        * 'IOC_OPAL_SAVE'.
+        * This allows integrating OPAL with tools and libraries that are used
+        * to the common behaviour and do not ask for the volume key when
+        * closing a device.
+        */
+       setup_opal_dev(dev);
+       list_for_each_entry(iter, &dev->unlk_lst, node) {
+               if ((iter->unlk.flags & OPAL_SAVE_FOR_LOCK) &&
+                               iter->lr == lk_unlk->session.opal_key.lr &&
+                               iter->unlk.session.opal_key.key_len > 0) {
+                       lk_unlk->session.opal_key.key_len =
+                               iter->unlk.session.opal_key.key_len;
+                       memcpy(lk_unlk->session.opal_key.key,
+                               iter->unlk.session.opal_key.key,
+                               iter->unlk.session.opal_key.key_len);
+                       break;
+               }
+       }
+}
+
 static int opal_lock_unlock(struct opal_dev *dev,
                            struct opal_lock_unlock *lk_unlk)
 {
@@ -2470,6 +2508,7 @@ static int opal_lock_unlock(struct opal_dev *dev,
                return -EINVAL;
 
        mutex_lock(&dev->dev_lock);
+       opal_lock_check_for_saved_key(dev, lk_unlk);
        ret = __opal_lock_unlock(dev, lk_unlk);
        mutex_unlock(&dev->dev_lock);