aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorAttila Fülöp <[email protected]>2021-10-21 06:06:55 +0200
committerBrian Behlendorf <[email protected]>2021-10-22 11:42:23 -0700
commit50292e2545bdf4886abe096ceede0cd1d95f49b0 (patch)
tree55a4735241e3625555fd407c756e7cac111afdf9 /contrib
parentee7c30b350ba6f67c7d1a293e9cbcfe13d7eb7f1 (diff)
pam_zfs_key: mlock(2) and munlock(2) can fail
Since both syscalls can fail, add error handling, including EAGAIN. Reviewed-by: Felix Dörre <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Attila Fülöp <[email protected]> Closes #12665
Diffstat (limited to 'contrib')
-rw-r--r--contrib/pam_zfs_key/pam_zfs_key.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/contrib/pam_zfs_key/pam_zfs_key.c b/contrib/pam_zfs_key/pam_zfs_key.c
index 0856c7534..e4196b7ad 100644
--- a/contrib/pam_zfs_key/pam_zfs_key.c
+++ b/contrib/pam_zfs_key/pam_zfs_key.c
@@ -54,7 +54,7 @@ pam_syslog(pam_handle_t *pamh, int loglevel, const char *fmt, ...)
#endif
#include <string.h>
-
+#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/file.h>
@@ -69,11 +69,38 @@ static libzfs_handle_t *g_zfs;
static void destroy_pw(pam_handle_t *pamh, void *data, int errcode);
+typedef int (*mlock_func_t) (const void *, size_t);
+
typedef struct {
size_t len;
char *value;
} pw_password_t;
+/*
+ * Try to mlock or munlock addr while handling EAGAIN by retrying ten times
+ * and sleeping 10 milliseconds in between for a total of 0.1 seconds.
+ * lock_func must point to either mlock(2) or munlock(2).
+ */
+static int
+try_lock(mlock_func_t lock_func, const void *addr, size_t len)
+{
+ int err;
+ int retries = 10;
+ useconds_t sleep_dur = 10 * 1000;
+
+ if ((err = (*lock_func)(addr, len)) != EAGAIN) {
+ return (err);
+ }
+ for (int i = retries; i > 0; --i) {
+ (void) usleep(sleep_dur);
+ if ((err = (*lock_func)(addr, len)) != EAGAIN) {
+ break;
+ }
+ }
+ return (err);
+}
+
+
static pw_password_t *
alloc_pw_size(size_t len)
{
@@ -91,7 +118,11 @@ alloc_pw_size(size_t len)
free(pw);
return (NULL);
}
- mlock(pw->value, pw->len);
+ if (try_lock(mlock, pw->value, pw->len) != 0) {
+ free(pw->value);
+ free(pw);
+ return NULL;
+ }
return (pw);
}
@@ -112,7 +143,11 @@ alloc_pw_string(const char *source)
free(pw);
return (NULL);
}
- mlock(pw->value, pw->len);
+ if (try_lock(mlock, pw->value, pw->len) != 0) {
+ free(pw->value);
+ free(pw);
+ return NULL;
+ }
memcpy(pw->value, source, pw->len);
return (pw);
}
@@ -121,8 +156,9 @@ static void
pw_free(pw_password_t *pw)
{
bzero(pw->value, pw->len);
- munlock(pw->value, pw->len);
- free(pw->value);
+ if (try_lock(munlock, pw->value, pw->len) == 0) {
+ free(pw->value);
+ }
free(pw);
}