From cd36d9f49f425e593443958a2788bbd6b08017f4 Mon Sep 17 00:00:00 2001 From: Steve Muckle Date: Fri, 5 May 2017 18:36:51 -0700 Subject: [PATCH 01/22] ANDROID: android-base.cfg: remove defunct options INET6_DIAG_DESTROY and NETFILTER_TPROXY are not used anymore so they should not be part of the base Android kernel configuration. Bug: 37749708 Change-Id: I59d0bf7d33a3b46e1f67f93f0b8e49eebbfce89c Signed-off-by: Steve Muckle --- kernel/configs/android-base.config | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index 30e01074f64a..748ccf37ca3e 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -29,7 +29,6 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_INET6_AH=y -CONFIG_INET6_DIAG_DESTROY=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_INET=y @@ -72,7 +71,6 @@ CONFIG_MODVERSIONS=y CONFIG_NET=y CONFIG_NETDEVICES=y CONFIG_NETFILTER=y -CONFIG_NETFILTER_TPROXY=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y From 2632fef6118ee249104cae3b25ba0698e2ae8f5c Mon Sep 17 00:00:00 2001 From: Steve Muckle Date: Sun, 7 May 2017 14:03:43 -0700 Subject: [PATCH 02/22] ANDROID: android-base.cfg: remove USB_OTG_WAKELOCK CONFIG_USB_OTG_WAKELOCK is currently somewhat outdated and as such is not applicable to all Android devices. Until it is brought up to date, remove it from the base Android kernel configuration. Bug: 37750863 Change-Id: I93d1d7204b46c5fe9f98455be9276a5bb38f6382 Signed-off-by: Steve Muckle --- kernel/configs/android-base.config | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index 748ccf37ca3e..3c32c74c584a 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -171,5 +171,4 @@ CONFIG_USB_CONFIGFS_F_MTP=y CONFIG_USB_CONFIGFS_F_PTP=y CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_GADGET=y -CONFIG_USB_OTG_WAKELOCK=y CONFIG_XFRM_USER=y From 00cca9768ebe1ac4ac16366662dd9087b6e5f4e7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 31 Jan 2017 15:24:03 +0100 Subject: [PATCH 03/22] timerfd: Protect the might cancel mechanism proper commit 1e38da300e1e395a15048b0af1e5305bd91402f6 upstream. The handling of the might_cancel queueing is not properly protected, so parallel operations on the file descriptor can race with each other and lead to list corruptions or use after free. Protect the context for these operations with a seperate lock. The wait queue lock cannot be reused for this because that would create a lock inversion scenario vs. the cancel lock. Replacing might_cancel with an atomic (atomic_t or atomic bit) does not help either because it still can race vs. the actual list operation. Reported-by: Dmitry Vyukov Signed-off-by: Thomas Gleixner Cc: "linux-fsdevel@vger.kernel.org" Cc: syzkaller Cc: Al Viro Cc: linux-fsdevel@vger.kernel.org Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1701311521430.3457@nanos Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- fs/timerfd.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/timerfd.c b/fs/timerfd.c index 9ae4abb4110b..ab8dd1538381 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -40,6 +40,7 @@ struct timerfd_ctx { short unsigned settime_flags; /* to show in fdinfo */ struct rcu_head rcu; struct list_head clist; + spinlock_t cancel_lock; bool might_cancel; }; @@ -112,7 +113,7 @@ void timerfd_clock_was_set(void) rcu_read_unlock(); } -static void timerfd_remove_cancel(struct timerfd_ctx *ctx) +static void __timerfd_remove_cancel(struct timerfd_ctx *ctx) { if (ctx->might_cancel) { ctx->might_cancel = false; @@ -122,6 +123,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx) } } +static void timerfd_remove_cancel(struct timerfd_ctx *ctx) +{ + spin_lock(&ctx->cancel_lock); + __timerfd_remove_cancel(ctx); + spin_unlock(&ctx->cancel_lock); +} + static bool timerfd_canceled(struct timerfd_ctx *ctx) { if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX) @@ -132,6 +140,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx) static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) { + spin_lock(&ctx->cancel_lock); if ((ctx->clockid == CLOCK_REALTIME || ctx->clockid == CLOCK_REALTIME_ALARM) && (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) { @@ -141,9 +150,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) list_add_rcu(&ctx->clist, &cancel_list); spin_unlock(&cancel_lock); } - } else if (ctx->might_cancel) { - timerfd_remove_cancel(ctx); + } else { + __timerfd_remove_cancel(ctx); } + spin_unlock(&ctx->cancel_lock); } static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx) @@ -400,6 +410,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) return -ENOMEM; init_waitqueue_head(&ctx->wqh); + spin_lock_init(&ctx->cancel_lock); ctx->clockid = clockid; if (isalarm(ctx)) From d8fd99d4721d4a33c928ee0de8370b294a2df150 Mon Sep 17 00:00:00 2001 From: Sachin Prabhu Date: Fri, 3 Mar 2017 15:41:38 -0800 Subject: [PATCH 04/22] Handle mismatched open calls commit 38bd49064a1ecb67baad33598e3d824448ab11ec upstream. A signal can interrupt a SendReceive call which result in incoming responses to the call being ignored. This is a problem for calls such as open which results in the successful response being ignored. This results in an open file resource on the server. The patch looks into responses which were cancelled after being sent and in case of successful open closes the open fids. For this patch, the check is only done in SendReceive2() RH-bz: 1403319 Signed-off-by: Sachin Prabhu Reviewed-by: Pavel Shilovsky Acked-by: Sachin Prabhu Signed-off-by: Pavel Shilovsky Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsglob.h | 11 ++++++++ fs/cifs/cifssmb.c | 4 +++ fs/cifs/connect.c | 13 +++++++-- fs/cifs/smb2misc.c | 44 ++++++++++++++++++++++++++++++ fs/cifs/smb2ops.c | 4 +++ fs/cifs/smb2proto.h | 7 +++++ fs/cifs/smb2transport.c | 60 ++++++++++++++++++++++++++++++++++++----- fs/cifs/transport.c | 2 ++ 8 files changed, 136 insertions(+), 9 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 94661cf77ae8..b3830f7ab260 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -241,6 +241,7 @@ struct smb_version_operations { /* verify the message */ int (*check_message)(char *, unsigned int, struct TCP_Server_Info *); bool (*is_oplock_break)(char *, struct TCP_Server_Info *); + int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *); void (*downgrade_oplock)(struct TCP_Server_Info *, struct cifsInodeInfo *, bool); /* process transaction2 response */ @@ -1314,12 +1315,19 @@ struct mid_q_entry { void *callback_data; /* general purpose pointer for callback */ void *resp_buf; /* pointer to received SMB header */ int mid_state; /* wish this were enum but can not pass to wait_event */ + unsigned int mid_flags; __le16 command; /* smb command code */ bool large_buf:1; /* if valid response, is pointer to large buf */ bool multiRsp:1; /* multiple trans2 responses for one request */ bool multiEnd:1; /* both received */ }; +struct close_cancelled_open { + struct cifs_fid fid; + struct cifs_tcon *tcon; + struct work_struct work; +}; + /* Make code in transport.c a little cleaner by moving update of optional stats into function below */ #ifdef CONFIG_CIFS_STATS2 @@ -1451,6 +1459,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, #define MID_RESPONSE_MALFORMED 0x10 #define MID_SHUTDOWN 0x20 +/* Flags */ +#define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */ + /* Types of response buffer returned from SendReceive2 */ #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ #define CIFS_SMALL_BUFFER 1 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e3fed9249a04..586fdac05ec2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1423,6 +1423,8 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) length = discard_remaining_data(server); dequeue_mid(mid, rdata->result); + mid->resp_buf = server->smallbuf; + server->smallbuf = NULL; return length; } @@ -1534,6 +1536,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) return cifs_readv_discard(server, mid); dequeue_mid(mid, false); + mid->resp_buf = server->smallbuf; + server->smallbuf = NULL; return length; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 893be0722643..b8015de88e8c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -882,10 +882,19 @@ cifs_demultiplex_thread(void *p) server->lstrp = jiffies; if (mid_entry != NULL) { + if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) && + mid_entry->mid_state == MID_RESPONSE_RECEIVED && + server->ops->handle_cancelled_mid) + server->ops->handle_cancelled_mid( + mid_entry->resp_buf, + server); + if (!mid_entry->multiRsp || mid_entry->multiEnd) mid_entry->callback(mid_entry); - } else if (!server->ops->is_oplock_break || - !server->ops->is_oplock_break(buf, server)) { + } else if (server->ops->is_oplock_break && + server->ops->is_oplock_break(buf, server)) { + cifs_dbg(FYI, "Received oplock break\n"); + } else { cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", atomic_read(&midCount)); cifs_dump_mem("Received Data is: ", buf, diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 3d383489b9cf..97307808ae42 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -654,3 +654,47 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n"); return false; } + +void +smb2_cancelled_close_fid(struct work_struct *work) +{ + struct close_cancelled_open *cancelled = container_of(work, + struct close_cancelled_open, work); + + cifs_dbg(VFS, "Close unmatched open\n"); + + SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid, + cancelled->fid.volatile_fid); + cifs_put_tcon(cancelled->tcon); + kfree(cancelled); +} + +int +smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) +{ + struct smb2_hdr *hdr = (struct smb2_hdr *)buffer; + struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer; + struct cifs_tcon *tcon; + struct close_cancelled_open *cancelled; + + if (hdr->Command != SMB2_CREATE || hdr->Status != STATUS_SUCCESS) + return 0; + + cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL); + if (!cancelled) + return -ENOMEM; + + tcon = smb2_find_smb_tcon(server, hdr->SessionId, hdr->TreeId); + if (!tcon) { + kfree(cancelled); + return -ENOENT; + } + + cancelled->fid.persistent_fid = rsp->PersistentFileId; + cancelled->fid.volatile_fid = rsp->VolatileFileId; + cancelled->tcon = tcon; + INIT_WORK(&cancelled->work, smb2_cancelled_close_fid); + queue_work(cifsiod_wq, &cancelled->work); + + return 0; +} diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 5d456ebb3813..007abf7195af 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1565,6 +1565,7 @@ struct smb_version_operations smb20_operations = { .clear_stats = smb2_clear_stats, .print_stats = smb2_print_stats, .is_oplock_break = smb2_is_valid_oplock_break, + .handle_cancelled_mid = smb2_handle_cancelled_mid, .downgrade_oplock = smb2_downgrade_oplock, .need_neg = smb2_need_neg, .negotiate = smb2_negotiate, @@ -1645,6 +1646,7 @@ struct smb_version_operations smb21_operations = { .clear_stats = smb2_clear_stats, .print_stats = smb2_print_stats, .is_oplock_break = smb2_is_valid_oplock_break, + .handle_cancelled_mid = smb2_handle_cancelled_mid, .downgrade_oplock = smb2_downgrade_oplock, .need_neg = smb2_need_neg, .negotiate = smb2_negotiate, @@ -1727,6 +1729,7 @@ struct smb_version_operations smb30_operations = { .print_stats = smb2_print_stats, .dump_share_caps = smb2_dump_share_caps, .is_oplock_break = smb2_is_valid_oplock_break, + .handle_cancelled_mid = smb2_handle_cancelled_mid, .downgrade_oplock = smb2_downgrade_oplock, .need_neg = smb2_need_neg, .negotiate = smb2_negotiate, @@ -1815,6 +1818,7 @@ struct smb_version_operations smb311_operations = { .print_stats = smb2_print_stats, .dump_share_caps = smb2_dump_share_caps, .is_oplock_break = smb2_is_valid_oplock_break, + .handle_cancelled_mid = smb2_handle_cancelled_mid, .downgrade_oplock = smb2_downgrade_oplock, .need_neg = smb2_need_neg, .negotiate = smb2_negotiate, diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index f2d511a6971b..04ef6e914597 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -48,6 +48,10 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst); extern struct mid_q_entry *smb2_setup_async_request( struct TCP_Server_Info *server, struct smb_rqst *rqst); +extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, + __u64 ses_id); +extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, + __u64 ses_id, __u32 tid); extern int smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server); extern int smb3_calc_signature(struct smb_rqst *rqst, @@ -158,6 +162,9 @@ extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, const u64 persistent_fid, const u64 volatile_fid, const __u8 oplock_level); +extern int smb2_handle_cancelled_mid(char *buffer, + struct TCP_Server_Info *server); +void smb2_cancelled_close_fid(struct work_struct *work); extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, struct kstatfs *FSData); diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index bc9a7b634643..390b0d0198f8 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -115,22 +115,68 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) } static struct cifs_ses * -smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server) +smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) { struct cifs_ses *ses; - spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { - if (ses->Suid != smb2hdr->SessionId) + if (ses->Suid != ses_id) continue; - spin_unlock(&cifs_tcp_ses_lock); return ses; } - spin_unlock(&cifs_tcp_ses_lock); return NULL; } +struct cifs_ses * +smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) +{ + struct cifs_ses *ses; + + spin_lock(&cifs_tcp_ses_lock); + ses = smb2_find_smb_ses_unlocked(server, ses_id); + spin_unlock(&cifs_tcp_ses_lock); + + return ses; +} + +static struct cifs_tcon * +smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid) +{ + struct cifs_tcon *tcon; + + list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { + if (tcon->tid != tid) + continue; + ++tcon->tc_count; + return tcon; + } + + return NULL; +} + +/* + * Obtain tcon corresponding to the tid in the given + * cifs_ses + */ + +struct cifs_tcon * +smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) +{ + struct cifs_ses *ses; + struct cifs_tcon *tcon; + + spin_lock(&cifs_tcp_ses_lock); + ses = smb2_find_smb_ses_unlocked(server, ses_id); + if (!ses) { + spin_unlock(&cifs_tcp_ses_lock); + return NULL; + } + tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); + spin_unlock(&cifs_tcp_ses_lock); + + return tcon; +} int smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) @@ -142,7 +188,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; struct cifs_ses *ses; - ses = smb2_find_smb_ses(smb2_pdu, server); + ses = smb2_find_smb_ses(server, smb2_pdu->SessionId); if (!ses) { cifs_dbg(VFS, "%s: Could not find session\n", __func__); return 0; @@ -359,7 +405,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; struct cifs_ses *ses; - ses = smb2_find_smb_ses(smb2_pdu, server); + ses = smb2_find_smb_ses(server, smb2_pdu->SessionId); if (!ses) { cifs_dbg(VFS, "%s: Could not find session\n", __func__); return 0; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 206a597b2293..cc26d4138d70 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -727,9 +727,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, rc = wait_for_response(ses->server, midQ); if (rc != 0) { + cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid); send_cancel(ses->server, buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { + midQ->mid_flags |= MID_WAIT_CANCELLED; midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(buf); From 1b7f385e049c46ae723126ccea343165e26a943f Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Fri, 13 Jan 2017 22:37:00 +0100 Subject: [PATCH 05/22] tpm_tis: use default timeout value if chip reports it as zero commit 1d70fe9d9c3a4c627f9757cbba5d628687b121c1 upstream. Since commit 1107d065fdf1 ("tpm_tis: Introduce intermediate layer for TPM access") Atmel 3203 TPM on ThinkPad X61S (TPM firmware version 13.9) no longer works. The initialization proceeds fine until we get and start using chip-reported timeouts - and the chip reports C and D timeouts of zero. It turns out that until commit 8e54caf407b98e ("tpm: Provide a generic means to override the chip returned timeouts") we had actually let default timeout values remain in this case, so let's bring back this behavior to make chips like Atmel 3203 work again. Use a common code that was introduced by that commit so a warning is printed in this case and /sys/class/tpm/tpm*/timeouts correctly says the timeouts aren't chip-original. This is a backport for 4.9 kernel version of the original commit, with renaming of "TPM_TIS_ITPM_POSSIBLE" flag removed since it was only a cosmetic change and not a part of the real bug fix. Fixes: 1107d065fdf1 ("tpm_tis: Introduce intermediate layer for TPM access") Cc: stable@vger.kernel.org Signed-off-by: Maciej S. Szmigiero Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-interface.c | 53 +++++++++++++++++++------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 3a9149cf0110..d0ac2d56520f 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -489,8 +489,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) int tpm_get_timeouts(struct tpm_chip *chip) { struct tpm_cmd_t tpm_cmd; - unsigned long new_timeout[4]; - unsigned long old_timeout[4]; + unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4]; struct duration_t *duration_cap; ssize_t rc; @@ -542,11 +541,15 @@ int tpm_get_timeouts(struct tpm_chip *chip) != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) return -EINVAL; - old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); - old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); - old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); - old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); - memcpy(new_timeout, old_timeout, sizeof(new_timeout)); + timeout_old[0] = jiffies_to_usecs(chip->timeout_a); + timeout_old[1] = jiffies_to_usecs(chip->timeout_b); + timeout_old[2] = jiffies_to_usecs(chip->timeout_c); + timeout_old[3] = jiffies_to_usecs(chip->timeout_d); + timeout_chip[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); + timeout_chip[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); + timeout_chip[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); + timeout_chip[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); + memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff)); /* * Provide ability for vendor overrides of timeout values in case @@ -554,16 +557,24 @@ int tpm_get_timeouts(struct tpm_chip *chip) */ if (chip->ops->update_timeouts != NULL) chip->timeout_adjusted = - chip->ops->update_timeouts(chip, new_timeout); + chip->ops->update_timeouts(chip, timeout_eff); if (!chip->timeout_adjusted) { - /* Don't overwrite default if value is 0 */ - if (new_timeout[0] != 0 && new_timeout[0] < 1000) { - int i; + /* Restore default if chip reported 0 */ + int i; + for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) { + if (timeout_eff[i]) + continue; + + timeout_eff[i] = timeout_old[i]; + chip->timeout_adjusted = true; + } + + if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) { /* timeouts in msec rather usec */ - for (i = 0; i != ARRAY_SIZE(new_timeout); i++) - new_timeout[i] *= 1000; + for (i = 0; i != ARRAY_SIZE(timeout_eff); i++) + timeout_eff[i] *= 1000; chip->timeout_adjusted = true; } } @@ -572,16 +583,16 @@ int tpm_get_timeouts(struct tpm_chip *chip) if (chip->timeout_adjusted) { dev_info(&chip->dev, HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", - old_timeout[0], new_timeout[0], - old_timeout[1], new_timeout[1], - old_timeout[2], new_timeout[2], - old_timeout[3], new_timeout[3]); + timeout_chip[0], timeout_eff[0], + timeout_chip[1], timeout_eff[1], + timeout_chip[2], timeout_eff[2], + timeout_chip[3], timeout_eff[3]); } - chip->timeout_a = usecs_to_jiffies(new_timeout[0]); - chip->timeout_b = usecs_to_jiffies(new_timeout[1]); - chip->timeout_c = usecs_to_jiffies(new_timeout[2]); - chip->timeout_d = usecs_to_jiffies(new_timeout[3]); + chip->timeout_a = usecs_to_jiffies(timeout_eff[0]); + chip->timeout_b = usecs_to_jiffies(timeout_eff[1]); + chip->timeout_c = usecs_to_jiffies(timeout_eff[2]); + chip->timeout_d = usecs_to_jiffies(timeout_eff[3]); duration: tpm_cmd.header.in = tpm_getcap_header; From d24261e567e12e85f2ecea39e512ee8de7d9858b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 7 Mar 2017 09:15:53 -0800 Subject: [PATCH 06/22] scsi: storvsc: Workaround for virtual DVD SCSI version commit f1c635b439a5c01776fe3a25b1e2dc546ea82e6f upstream. Hyper-V host emulation of SCSI for virtual DVD device reports SCSI version 0 (UNKNOWN) but is still capable of supporting REPORTLUN. Without this patch, a GEN2 Linux guest on Hyper-V will not boot 4.11 successfully with virtual DVD ROM device. What happens is that the SCSI scan process falls back to doing sequential probing by INQUIRY. But the storvsc driver has a previous workaround that masks/blocks all errors reports from INQUIRY (or MODE_SENSE) commands. This workaround causes the scan to then populate a full set of bogus LUN's on the target and then sends kernel spinning off into a death spiral doing block reads on the non-existent LUNs. By setting the correct blacklist flags, the target with the DVD device is scanned with REPORTLUN and that works correctly. Patch needs to go in current 4.11, it is safe but not necessary in older kernels. Signed-off-by: Stephen Hemminger Reviewed-by: K. Y. Srinivasan Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/storvsc_drv.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 3f218f5cf29b..c5ab1b0037fc 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -400,8 +400,6 @@ MODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels") */ static int storvsc_timeout = 180; -static int msft_blist_flags = BLIST_TRY_VPD_PAGES; - #if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) static struct scsi_transport_template *fc_transport_template; #endif @@ -1283,6 +1281,22 @@ static int storvsc_do_io(struct hv_device *device, return ret; } +static int storvsc_device_alloc(struct scsi_device *sdevice) +{ + /* + * Set blist flag to permit the reading of the VPD pages even when + * the target may claim SPC-2 compliance. MSFT targets currently + * claim SPC-2 compliance while they implement post SPC-2 features. + * With this flag we can correctly handle WRITE_SAME_16 issues. + * + * Hypervisor reports SCSI_UNKNOWN type for DVD ROM device but + * still supports REPORT LUN. + */ + sdevice->sdev_bflags = BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES; + + return 0; +} + static int storvsc_device_configure(struct scsi_device *sdevice) { @@ -1297,14 +1311,6 @@ static int storvsc_device_configure(struct scsi_device *sdevice) sdevice->no_write_same = 1; - /* - * Add blist flags to permit the reading of the VPD pages even when - * the target may claim SPC-2 compliance. MSFT targets currently - * claim SPC-2 compliance while they implement post SPC-2 features. - * With this patch we can correctly handle WRITE_SAME_16 issues. - */ - sdevice->sdev_bflags |= msft_blist_flags; - /* * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3 * if the device is a MSFT virtual device. If the host is @@ -1569,6 +1575,7 @@ static struct scsi_host_template scsi_driver = { .eh_host_reset_handler = storvsc_host_reset_handler, .proc_name = "storvsc_host", .eh_timed_out = storvsc_eh_timed_out, + .slave_alloc = storvsc_device_alloc, .slave_configure = storvsc_device_configure, .cmd_per_lun = 255, .this_id = -1, From 3fbd2ba1da3f79e0352e6c772fab964c3ad963a3 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 12 Mar 2017 06:18:58 -0700 Subject: [PATCH 07/22] hwmon: (it87) Avoid registering the same chip on both SIO addresses commit 8358378b22518d92424597503d3c1cd302a490b6 upstream. IT8705F is known to respond on both SIO addresses. Registering it twice may result in system lockups. Reported-by: Russell King Fixes: e84bd9535e2b ("hwmon: (it87) Add support for second Super-IO chip") Signed-off-by: Guenter Roeck Cc: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/it87.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 43146162c122..b99c1df48156 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -3115,7 +3115,7 @@ static int __init sm_it87_init(void) { int sioaddr[2] = { REG_2E, REG_4E }; struct it87_sio_data sio_data; - unsigned short isa_address; + unsigned short isa_address[2]; bool found = false; int i, err; @@ -3125,15 +3125,29 @@ static int __init sm_it87_init(void) for (i = 0; i < ARRAY_SIZE(sioaddr); i++) { memset(&sio_data, 0, sizeof(struct it87_sio_data)); - isa_address = 0; - err = it87_find(sioaddr[i], &isa_address, &sio_data); - if (err || isa_address == 0) + isa_address[i] = 0; + err = it87_find(sioaddr[i], &isa_address[i], &sio_data); + if (err || isa_address[i] == 0) continue; + /* + * Don't register second chip if its ISA address matches + * the first chip's ISA address. + */ + if (i && isa_address[i] == isa_address[0]) + break; - err = it87_device_add(i, isa_address, &sio_data); + err = it87_device_add(i, isa_address[i], &sio_data); if (err) goto exit_dev_unregister; + found = true; + + /* + * IT8705F may respond on both SIO addresses. + * Stop probing after finding one. + */ + if (sio_data.type == it87) + break; } if (!found) { From 1bf9bc48133851121d92f0cc908bb5a1446aeba5 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Wed, 28 Dec 2016 16:42:00 -0200 Subject: [PATCH 08/22] 8250_pci: Fix potential use-after-free in error path commit c130b666a9a711f985a0a44b58699ebe14bb7245 upstream. Commit f209fa03fc9d ("serial: 8250_pci: Detach low-level driver during PCI error recovery") introduces a potential use-after-free in case the pciserial_init_ports call in serial8250_io_resume fails, which may happen if a memory allocation fails or if the .init quirk failed for whatever reason). If this happen, further pci_get_drvdata will return a pointer to freed memory. This patch reworks the PCI recovery resume hook to restore the old priv structure in this case, which should be ok, since the ports were already detached. Such error during recovery causes us to give up on the recovery. Fixes: f209fa03fc9d ("serial: 8250_pci: Detach low-level driver during PCI error recovery") Reported-by: Michal Suchanek Signed-off-by: Gabriel Krisman Bertazi Signed-off-by: Guilherme G. Piccoli Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 6e3e63675e56..22d32d295c5b 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -5621,17 +5621,15 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev) static void serial8250_io_resume(struct pci_dev *dev) { struct serial_private *priv = pci_get_drvdata(dev); - const struct pciserial_board *board; + struct serial_private *new; if (!priv) return; - board = priv->board; - kfree(priv); - priv = pciserial_init_ports(dev, board); - - if (!IS_ERR(priv)) { - pci_set_drvdata(dev, priv); + new = pciserial_init_ports(dev, priv->board); + if (!IS_ERR(new)) { + pci_set_drvdata(dev, new); + kfree(priv); } } From e99b0ea39354cf308423588df5daf69c42dbd735 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 25 Oct 2016 10:51:55 +0800 Subject: [PATCH 09/22] ceph: try getting buffer capability for readahead/fadvise commit 2b1ac852eb67a6e95595e576371d23519105559f upstream. For readahead/fadvise cases, caller of ceph_readpages does not hold buffer capability. Pages can be added to page cache while there is no buffer capability. This can cause data integrity issue. Signed-off-by: Yan, Zheng Signed-off-by: Greg Kroah-Hartman --- fs/ceph/addr.c | 58 ++++++++++++++++++++++++++++++++++++++++--------- fs/ceph/caps.c | 21 ++++++++++++++++++ fs/ceph/file.c | 3 ++- fs/ceph/super.h | 2 ++ 4 files changed, 73 insertions(+), 11 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 1e643c718917..18dc18f8af2c 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -315,7 +315,32 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) struct page **pages; pgoff_t next_index; int nr_pages = 0; - int ret; + int got = 0; + int ret = 0; + + if (!current->journal_info) { + /* caller of readpages does not hold buffer and read caps + * (fadvise, madvise and readahead cases) */ + int want = CEPH_CAP_FILE_CACHE; + ret = ceph_try_get_caps(ci, CEPH_CAP_FILE_RD, want, &got); + if (ret < 0) { + dout("start_read %p, error getting cap\n", inode); + } else if (!(got & want)) { + dout("start_read %p, no cache cap\n", inode); + ret = 0; + } + if (ret <= 0) { + if (got) + ceph_put_cap_refs(ci, got); + while (!list_empty(page_list)) { + page = list_entry(page_list->prev, + struct page, lru); + list_del(&page->lru); + put_page(page); + } + return ret; + } + } off = (u64) page_offset(page); @@ -338,15 +363,18 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) CEPH_OSD_FLAG_READ, NULL, ci->i_truncate_seq, ci->i_truncate_size, false); - if (IS_ERR(req)) - return PTR_ERR(req); + if (IS_ERR(req)) { + ret = PTR_ERR(req); + goto out; + } /* build page vector */ nr_pages = calc_pages_for(0, len); pages = kmalloc(sizeof(*pages) * nr_pages, GFP_KERNEL); - ret = -ENOMEM; - if (!pages) - goto out; + if (!pages) { + ret = -ENOMEM; + goto out_put; + } for (i = 0; i < nr_pages; ++i) { page = list_entry(page_list->prev, struct page, lru); BUG_ON(PageLocked(page)); @@ -379,6 +407,12 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) if (ret < 0) goto out_pages; ceph_osdc_put_request(req); + + /* After adding locked pages to page cache, the inode holds cache cap. + * So we can drop our cap refs. */ + if (got) + ceph_put_cap_refs(ci, got); + return nr_pages; out_pages: @@ -387,8 +421,11 @@ out_pages: unlock_page(pages[i]); } ceph_put_page_vector(pages, nr_pages, false); -out: +out_put: ceph_osdc_put_request(req); +out: + if (got) + ceph_put_cap_refs(ci, got); return ret; } @@ -425,7 +462,6 @@ static int ceph_readpages(struct file *file, struct address_space *mapping, rc = start_read(inode, page_list, max); if (rc < 0) goto out; - BUG_ON(rc == 0); } out: ceph_fscache_readpages_cancel(inode, page_list); @@ -1372,9 +1408,11 @@ static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) inode, off, (size_t)PAGE_SIZE, ceph_cap_string(got)); if ((got & (CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO)) || - ci->i_inline_version == CEPH_INLINE_NONE) + ci->i_inline_version == CEPH_INLINE_NONE) { + current->journal_info = vma->vm_file; ret = filemap_fault(vma, vmf); - else + current->journal_info = NULL; + } else ret = -EAGAIN; dout("filemap_fault %p %llu~%zd dropping cap refs on %s ret %d\n", diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index f3f21105b860..03951f90ecf7 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2479,6 +2479,27 @@ static void check_max_size(struct inode *inode, loff_t endoff) ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); } +int ceph_try_get_caps(struct ceph_inode_info *ci, int need, int want, int *got) +{ + int ret, err = 0; + + BUG_ON(need & ~CEPH_CAP_FILE_RD); + BUG_ON(want & ~(CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)); + ret = ceph_pool_perm_check(ci, need); + if (ret < 0) + return ret; + + ret = try_get_cap_refs(ci, need, want, 0, true, got, &err); + if (ret) { + if (err == -EAGAIN) { + ret = 0; + } else if (err < 0) { + ret = err; + } + } + return ret; +} + /* * Wait for caps, and take cap references. If we can't get a WR cap * due to a small max_size, make sure we check_max_size (and possibly diff --git a/fs/ceph/file.c b/fs/ceph/file.c index f995e3528a33..ca3f630db90f 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -1249,8 +1249,9 @@ again: dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n", inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len, ceph_cap_string(got)); - + current->journal_info = filp; ret = generic_file_read_iter(iocb, to); + current->journal_info = NULL; } dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n", inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 3e3fa9163059..622d5dd9f616 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -905,6 +905,8 @@ extern int ceph_encode_dentry_release(void **p, struct dentry *dn, extern int ceph_get_caps(struct ceph_inode_info *ci, int need, int want, loff_t endoff, int *got, struct page **pinned_page); +extern int ceph_try_get_caps(struct ceph_inode_info *ci, + int need, int want, int *got); /* for counting open files by mode */ extern void __ceph_get_fmode(struct ceph_inode_info *ci, int mode); From 7ad6de43deda083f1eab1e9a5cc48166e4ee52f5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 14 Mar 2017 16:06:45 +0100 Subject: [PATCH 10/22] cpu/hotplug: Serialize callback invocations proper commit dc434e056fe1dada20df7ba07f32739d3a701adf upstream. The setup/remove_state/instance() functions in the hotplug core code are serialized against concurrent CPU hotplug, but unfortunately not serialized against themself. As a consequence a concurrent invocation of these function results in corruption of the callback machinery because two instances try to invoke callbacks on remote cpus at the same time. This results in missing callback invocations and initiator threads waiting forever on the completion. The obvious solution to replace get_cpu_online() with cpu_hotplug_begin() is not possible because at least one callsite calls into these functions from a get_online_cpu() locked region. Extend the protection scope of the cpuhp_state_mutex from solely protecting the state arrays to cover the callback invocation machinery as well. Fixes: 5b7aa87e0482 ("cpu/hotplug: Implement setup/removal interface") Reported-and-tested-by: Bart Van Assche Signed-off-by: Sebastian Andrzej Siewior Cc: hpa@zytor.com Cc: mingo@kernel.org Cc: akpm@linux-foundation.org Cc: torvalds@linux-foundation.org Link: http://lkml.kernel.org/r/20170314150645.g4tdyoszlcbajmna@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Greg Kroah-Hartman --- kernel/cpu.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/kernel/cpu.c b/kernel/cpu.c index 217fd2e7f435..99c6c568bc55 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1441,14 +1441,12 @@ static void cpuhp_store_callbacks(enum cpuhp_state state, /* (Un)Install the callbacks for further cpu hotplug operations */ struct cpuhp_step *sp; - mutex_lock(&cpuhp_state_mutex); sp = cpuhp_get_step(state); sp->startup.single = startup; sp->teardown.single = teardown; sp->name = name; sp->multi_instance = multi_instance; INIT_HLIST_HEAD(&sp->list); - mutex_unlock(&cpuhp_state_mutex); } static void *cpuhp_get_teardown_cb(enum cpuhp_state state) @@ -1518,16 +1516,13 @@ static int cpuhp_reserve_state(enum cpuhp_state state) { enum cpuhp_state i; - mutex_lock(&cpuhp_state_mutex); for (i = CPUHP_AP_ONLINE_DYN; i <= CPUHP_AP_ONLINE_DYN_END; i++) { if (cpuhp_ap_states[i].name) continue; cpuhp_ap_states[i].name = "Reserved"; - mutex_unlock(&cpuhp_state_mutex); return i; } - mutex_unlock(&cpuhp_state_mutex); WARN(1, "No more dynamic states available for CPU hotplug\n"); return -ENOSPC; } @@ -1544,6 +1539,7 @@ int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node, return -EINVAL; get_online_cpus(); + mutex_lock(&cpuhp_state_mutex); if (!invoke || !sp->startup.multi) goto add_node; @@ -1568,11 +1564,10 @@ int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node, } add_node: ret = 0; - mutex_lock(&cpuhp_state_mutex); hlist_add_head(node, &sp->list); - mutex_unlock(&cpuhp_state_mutex); err: + mutex_unlock(&cpuhp_state_mutex); put_online_cpus(); return ret; } @@ -1601,6 +1596,7 @@ int __cpuhp_setup_state(enum cpuhp_state state, return -EINVAL; get_online_cpus(); + mutex_lock(&cpuhp_state_mutex); /* currently assignments for the ONLINE state are possible */ if (state == CPUHP_AP_ONLINE_DYN) { @@ -1636,6 +1632,8 @@ int __cpuhp_setup_state(enum cpuhp_state state, } } out: + mutex_unlock(&cpuhp_state_mutex); + put_online_cpus(); if (!ret && dyn_state) return state; @@ -1655,6 +1653,8 @@ int __cpuhp_state_remove_instance(enum cpuhp_state state, return -EINVAL; get_online_cpus(); + mutex_lock(&cpuhp_state_mutex); + if (!invoke || !cpuhp_get_teardown_cb(state)) goto remove; /* @@ -1671,7 +1671,6 @@ int __cpuhp_state_remove_instance(enum cpuhp_state state, } remove: - mutex_lock(&cpuhp_state_mutex); hlist_del(node); mutex_unlock(&cpuhp_state_mutex); put_online_cpus(); @@ -1696,6 +1695,7 @@ void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) BUG_ON(cpuhp_cb_check(state)); get_online_cpus(); + mutex_lock(&cpuhp_state_mutex); if (sp->multi_instance) { WARN(!hlist_empty(&sp->list), @@ -1721,6 +1721,7 @@ void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) } remove: cpuhp_store_callbacks(state, NULL, NULL, NULL, false); + mutex_unlock(&cpuhp_state_mutex); put_online_cpus(); } EXPORT_SYMBOL(__cpuhp_remove_state); From a0d50c80a29e13a56f9830d0b4bc6e333fc09da2 Mon Sep 17 00:00:00 2001 From: Adrian Salido Date: Thu, 27 Apr 2017 10:32:55 -0700 Subject: [PATCH 11/22] dm ioctl: prevent stack leak in dm ioctl call commit 4617f564c06117c7d1b611be49521a4430042287 upstream. When calling a dm ioctl that doesn't process any data (IOCTL_FLAGS_NO_PARAMS), the contents of the data field in struct dm_ioctl are left initialized. Current code is incorrectly extending the size of data copied back to user, causing the contents of kernel stack to be leaked to user. Fix by only copying contents before data and allow the functions processing the ioctl to override. Signed-off-by: Adrian Salido Reviewed-by: Alasdair G Kergon Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 966eb4b61aed..a68c650aad11 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1847,7 +1847,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) if (r) goto out; - param->data_size = sizeof(*param); + param->data_size = offsetof(struct dm_ioctl, data); r = fn(param, input_param_size); if (unlikely(param->flags & DM_BUFFER_FULL_FLAG) && From 89f3b8d5f264d5dab9818c6667c71e3cc55b13f5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 8 May 2017 07:48:32 +0200 Subject: [PATCH 12/22] Linux 4.9.27 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c09679c1a70d..35d6b4e76264 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 26 +SUBLEVEL = 27 EXTRAVERSION = NAME = Roaring Lionus From 875e52672dbf33a31a830dfd1326ac8af582b29f Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Wed, 19 Apr 2017 14:22:47 -0700 Subject: [PATCH 13/22] ANDROID: Add untag hacks to inet_release function To prevent protential risk of memory leak caused by closing socket with out untag it from qtaguid module, the qtaguid module now do not hold any socket file reference count. Instead, it will increase the sk_refcnt of the sk struct to prevent a reuse of the socket pointer. And when a socket is released. It will delete the tag if the socket is previously tagged so no more resources is held by xt_qtaguid moudle. A flag is added to the untag process to prevent possible kernel crash caused by fail to delete corresponding socket_tag_entry list. Bug: 36374484 Test: compile and run test under system/extra/test/iptables, run cts -m CtsNetTestCases -t android.net.cts.SocketRefCntTest Signed-off-by: Chenbo Feng Change-Id: Iea7c3bf0c59b9774a5114af905b2405f6bc9ee52 --- include/linux/netfilter/xt_qtaguid.h | 1 + net/ipv4/af_inet.c | 4 + net/netfilter/xt_qtaguid.c | 107 ++++++++++++++------------- net/netfilter/xt_qtaguid_internal.h | 2 - net/netfilter/xt_qtaguid_print.c | 8 +- 5 files changed, 63 insertions(+), 59 deletions(-) diff --git a/include/linux/netfilter/xt_qtaguid.h b/include/linux/netfilter/xt_qtaguid.h index ca60fbdec2f3..1c671552ec37 100644 --- a/include/linux/netfilter/xt_qtaguid.h +++ b/include/linux/netfilter/xt_qtaguid.h @@ -10,4 +10,5 @@ #define XT_QTAGUID_SOCKET XT_OWNER_SOCKET #define xt_qtaguid_match_info xt_owner_match_info +int qtaguid_untag(struct socket *sock, bool kernel); #endif /* _XT_QTAGUID_MATCH_H */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8bc6c4e52fe5..39e9acfb59a4 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -89,6 +89,7 @@ #include #include #include +#include #include @@ -412,6 +413,9 @@ int inet_release(struct socket *sock) if (sk) { long timeout; +#ifdef CONFIG_NETFILTER_XT_MATCH_QTAGUID + qtaguid_untag(sock, true); +#endif /* Applications forget to leave groups before exiting */ ip_mc_drop_socket(sk); diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index 3c7ae04751a4..1fbe4b6ad462 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -321,7 +321,7 @@ static void sock_tag_tree_erase(struct rb_root *st_to_free_tree) st_entry->tag, get_uid_from_tag(st_entry->tag)); rb_erase(&st_entry->sock_node, st_to_free_tree); - sockfd_put(st_entry->socket); + sock_put(st_entry->sk); kfree(st_entry); } } @@ -1922,12 +1922,12 @@ static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v) { struct sock_tag *sock_tag_entry = v; uid_t uid; - long f_count; CT_DEBUG("qtaguid: proc ctrl pid=%u tgid=%u uid=%u\n", current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); if (sock_tag_entry != SEQ_START_TOKEN) { + int sk_ref_count; uid = get_uid_from_tag(sock_tag_entry->tag); CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u) " "pid=%u\n", @@ -1936,13 +1936,13 @@ static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v) uid, sock_tag_entry->pid ); - f_count = atomic_long_read( - &sock_tag_entry->socket->file->f_count); + sk_ref_count = atomic_read( + &sock_tag_entry->sk->sk_refcnt); seq_printf(m, "sock=%pK tag=0x%llx (uid=%u) pid=%u " - "f_count=%lu\n", + "f_count=%d\n", sock_tag_entry->sk, sock_tag_entry->tag, uid, - sock_tag_entry->pid, f_count); + sock_tag_entry->pid, sk_ref_count); } else { seq_printf(m, "events: sockets_tagged=%llu " "sockets_untagged=%llu " @@ -2238,8 +2238,8 @@ static int ctrl_cmd_tag(const char *input) from_kuid(&init_user_ns, current_fsuid())); goto err; } - CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%ld ->sk=%p\n", - input, atomic_long_read(&el_socket->file->f_count), + CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->sk_refcnt=%d ->sk=%p\n", + input, atomic_read(&el_socket->sk->sk_refcnt), el_socket->sk); if (argc < 3) { acct_tag = make_atag_from_value(0); @@ -2283,16 +2283,9 @@ static int ctrl_cmd_tag(const char *input) struct tag_ref *prev_tag_ref_entry; CT_DEBUG("qtaguid: ctrl_tag(%s): retag for sk=%p " - "st@%p ...->f_count=%ld\n", + "st@%p ...->sk_refcnt=%d\n", input, el_socket->sk, sock_tag_entry, - atomic_long_read(&el_socket->file->f_count)); - /* - * This is a re-tagging, so release the sock_fd that was - * locked at the time of the 1st tagging. - * There is still the ref from this call's sockfd_lookup() so - * it can be done within the spinlock. - */ - sockfd_put(sock_tag_entry->socket); + atomic_read(&el_socket->sk->sk_refcnt)); prev_tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag, &uid_tag_data_entry); BUG_ON(IS_ERR_OR_NULL(prev_tag_ref_entry)); @@ -2312,8 +2305,12 @@ static int ctrl_cmd_tag(const char *input) res = -ENOMEM; goto err_tag_unref_put; } + /* + * Hold the sk refcount here to make sure the sk pointer cannot + * be freed and reused + */ + sock_hold(el_socket->sk); sock_tag_entry->sk = el_socket->sk; - sock_tag_entry->socket = el_socket; sock_tag_entry->pid = current->tgid; sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid_int); spin_lock_bh(&uid_tag_data_tree_lock); @@ -2340,10 +2337,11 @@ static int ctrl_cmd_tag(const char *input) atomic64_inc(&qtu_events.sockets_tagged); } spin_unlock_bh(&sock_tag_list_lock); - /* We keep the ref to the socket (file) until it is untagged */ - CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->f_count=%ld\n", + /* We keep the ref to the sk until it is untagged */ + CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->sk_refcnt=%d\n", input, sock_tag_entry, - atomic_long_read(&el_socket->file->f_count)); + atomic_read(&el_socket->sk->sk_refcnt)); + sockfd_put(el_socket); return 0; err_tag_unref_put: @@ -2351,8 +2349,8 @@ err_tag_unref_put: tag_ref_entry->num_sock_tags--; free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry); err_put: - CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->f_count=%ld\n", - input, atomic_long_read(&el_socket->file->f_count) - 1); + CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->sk_refcnt=%d\n", + input, atomic_read(&el_socket->sk->sk_refcnt) - 1); /* Release the sock_fd that was grabbed by sockfd_lookup(). */ sockfd_put(el_socket); return res; @@ -2368,17 +2366,13 @@ static int ctrl_cmd_untag(const char *input) int sock_fd = 0; struct socket *el_socket; int res, argc; - struct sock_tag *sock_tag_entry; - struct tag_ref *tag_ref_entry; - struct uid_tag_data *utd_entry; - struct proc_qtu_data *pqd_entry; argc = sscanf(input, "%c %d", &cmd, &sock_fd); CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n", input, argc, cmd, sock_fd); if (argc < 2) { res = -EINVAL; - goto err; + return res; } el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */ if (!el_socket) { @@ -2386,17 +2380,31 @@ static int ctrl_cmd_untag(const char *input) " sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n", input, sock_fd, res, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); - goto err; + return res; } CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%ld ->sk=%p\n", input, atomic_long_read(&el_socket->file->f_count), el_socket->sk); + res = qtaguid_untag(el_socket, false); + sockfd_put(el_socket); + return res; +} + +int qtaguid_untag(struct socket *el_socket, bool kernel) +{ + int res; + pid_t pid; + struct sock_tag *sock_tag_entry; + struct tag_ref *tag_ref_entry; + struct uid_tag_data *utd_entry; + struct proc_qtu_data *pqd_entry; + spin_lock_bh(&sock_tag_list_lock); sock_tag_entry = get_sock_stat_nl(el_socket->sk); if (!sock_tag_entry) { spin_unlock_bh(&sock_tag_list_lock); res = -EINVAL; - goto err_put; + return res; } /* * The socket already belongs to the current process @@ -2408,20 +2416,26 @@ static int ctrl_cmd_untag(const char *input) BUG_ON(!tag_ref_entry); BUG_ON(tag_ref_entry->num_sock_tags <= 0); spin_lock_bh(&uid_tag_data_tree_lock); + if (kernel) + pid = sock_tag_entry->pid; + else + pid = current->tgid; pqd_entry = proc_qtu_data_tree_search( - &proc_qtu_data_tree, current->tgid); + &proc_qtu_data_tree, pid); /* * TODO: remove if, and start failing. * At first, we want to catch user-space code that is not * opening the /dev/xt_qtaguid. */ - if (IS_ERR_OR_NULL(pqd_entry)) + if (IS_ERR_OR_NULL(pqd_entry) || !sock_tag_entry->list.next) { pr_warn_once("qtaguid: %s(): " "User space forgot to open /dev/xt_qtaguid? " - "pid=%u tgid=%u uid=%u\n", __func__, - current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); - else + "pid=%u tgid=%u sk_pid=%u, uid=%u\n", __func__, + current->pid, current->tgid, sock_tag_entry->pid, + from_kuid(&init_user_ns, current_fsuid())); + } else { list_del(&sock_tag_entry->list); + } spin_unlock_bh(&uid_tag_data_tree_lock); /* * We don't free tag_ref from the utd_entry here, @@ -2430,30 +2444,17 @@ static int ctrl_cmd_untag(const char *input) tag_ref_entry->num_sock_tags--; spin_unlock_bh(&sock_tag_list_lock); /* - * Release the sock_fd that was grabbed at tag time, - * and once more for the sockfd_lookup() here. + * Release the sock_fd that was grabbed at tag time. */ - sockfd_put(sock_tag_entry->socket); - CT_DEBUG("qtaguid: ctrl_untag(%s): done. st@%p ...->f_count=%ld\n", - input, sock_tag_entry, - atomic_long_read(&el_socket->file->f_count) - 1); - sockfd_put(el_socket); + sock_put(sock_tag_entry->sk); + CT_DEBUG("qtaguid: done. st@%p ...->sk_refcnt=%d\n", + sock_tag_entry, + atomic_read(&el_socket->sk->sk_refcnt)); kfree(sock_tag_entry); atomic64_inc(&qtu_events.sockets_untagged); return 0; - -err_put: - CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%ld\n", - input, atomic_long_read(&el_socket->file->f_count) - 1); - /* Release the sock_fd that was grabbed by sockfd_lookup(). */ - sockfd_put(el_socket); - return res; - -err: - CT_DEBUG("qtaguid: ctrl_untag(%s): done.\n", input); - return res; } static ssize_t qtaguid_ctrl_parse(const char *input, size_t count) diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h index 6dc14a9c6889..8178fbdfb036 100644 --- a/net/netfilter/xt_qtaguid_internal.h +++ b/net/netfilter/xt_qtaguid_internal.h @@ -256,8 +256,6 @@ struct iface_stat_work { struct sock_tag { struct rb_node sock_node; struct sock *sk; /* Only used as a number, never dereferenced */ - /* The socket is needed for sockfd_put() */ - struct socket *socket; /* Used to associate with a given pid */ struct list_head list; /* in proc_qtu_data.sock_tag_list */ pid_t pid; diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c index f6a00a3520ed..2a7190d285e6 100644 --- a/net/netfilter/xt_qtaguid_print.c +++ b/net/netfilter/xt_qtaguid_print.c @@ -24,7 +24,7 @@ #include #include #include - +#include #include "xt_qtaguid_internal.h" #include "xt_qtaguid_print.h" @@ -237,10 +237,10 @@ char *pp_sock_tag(struct sock_tag *st) tag_str = pp_tag_t(&st->tag); res = kasprintf(GFP_ATOMIC, "sock_tag@%p{" "sock_node=rb_node{...}, " - "sk=%p socket=%p (f_count=%lu), list=list_head{...}, " + "sk=%p (f_count=%d), list=list_head{...}, " "pid=%u, tag=%s}", - st, st->sk, st->socket, atomic_long_read( - &st->socket->file->f_count), + st, st->sk, atomic_read( + &st->sk->sk_refcnt), st->pid, tag_str); _bug_on_err_or_null(res); kfree(tag_str); From cac7ba9118f3ca98541e59938142ce55340664e4 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 20 Apr 2017 18:05:02 -0700 Subject: [PATCH 14/22] ANDROID: sdcardfs: Use filesystem specific hash We weren't accounting for FS specific hash functions, causing us to miss negative dentries for any FS that had one. Similar to a patch from esdfs commit 75bd25a9476d ("esdfs: support lower's own hash") Signed-off-by: Daniel Rosenberg Change-Id: I32d1ba304d728e0ca2648cacfb4c2e441ae63608 --- fs/sdcardfs/lookup.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 19154b77b0fc..78c44ed70bf2 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -366,8 +366,13 @@ put_name: /* instatiate a new negative dentry */ dname.name = name->name; dname.len = name->len; - dname.hash = full_name_hash(lower_dir_dentry, dname.name, dname.len); - lower_dentry = d_lookup(lower_dir_dentry, &dname); + + /* See if the low-level filesystem might want + * to use its own hash + */ + lower_dentry = d_hash_and_lookup(lower_dir_dentry, &dname); + if (IS_ERR(lower_dentry)) + return lower_dentry; if (lower_dentry) goto setup_lower; From 579687073da55b419a1245ee203b11ea68748040 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 20 Apr 2017 18:21:50 -0700 Subject: [PATCH 15/22] Revert "Revert "Android: sdcardfs: Don't do d_add for lower fs"" This reverts commit ffa75fdb9c408f49b9622b6d55752ed99ff61488. Turns out we just needed the right hash. Signed-off-by: Daniel Rosenberg Bug: 37231161 Change-Id: I6a6de7f7df99ad42b20fa062913b219f64020c31 --- fs/sdcardfs/lookup.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 78c44ed70bf2..706329dd1ca3 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -373,17 +373,15 @@ put_name: lower_dentry = d_hash_and_lookup(lower_dir_dentry, &dname); if (IS_ERR(lower_dentry)) return lower_dentry; - if (lower_dentry) - goto setup_lower; - - lower_dentry = d_alloc(lower_dir_dentry, &dname); if (!lower_dentry) { - err = -ENOMEM; + /* We called vfs_path_lookup earlier, and did not get a negative + * dentry then. Don't confuse the lower filesystem by forcing + * one on it now... + */ + err = -ENOENT; goto out; } - d_add(lower_dentry, NULL); /* instantiate and hash */ -setup_lower: lower_path.dentry = lower_dentry; lower_path.mnt = mntget(lower_dir_mnt); sdcardfs_set_lower_path(dentry, &lower_path); From 4131f8ccf7302c58a7f40bfd316d08a496389aed Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 24 Apr 2017 16:10:21 -0700 Subject: [PATCH 16/22] ANDROID: sdcardfs: Copy meta-data from lower inode From wrapfs commit 3ee9b365e38c ("Wrapfs: properly copy meta-data after AIO operations from lower inode") Signed-off-by: Daniel Rosenberg Bug: 35766959 Change-Id: I9a789222e27a17b8d85ce61c45397d1839f9a675 --- fs/sdcardfs/file.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 1f6921e2ffbf..6076c342dae6 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -358,9 +358,12 @@ ssize_t sdcardfs_read_iter(struct kiocb *iocb, struct iov_iter *iter) get_file(lower_file); /* prevent lower_file from being released */ iocb->ki_filp = lower_file; err = lower_file->f_op->read_iter(iocb, iter); - /* ? wait IO finish to update atime as ecryptfs ? */ iocb->ki_filp = file; fput(lower_file); + /* update upper inode atime as needed */ + if (err >= 0 || err == -EIOCBQUEUED) + fsstack_copy_attr_atime(file->f_path.dentry->d_inode, + file_inode(lower_file)); out: return err; } @@ -384,6 +387,13 @@ ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter) err = lower_file->f_op->write_iter(iocb, iter); iocb->ki_filp = file; fput(lower_file); + /* update upper inode times/sizes as needed */ + if (err >= 0 || err == -EIOCBQUEUED) { + fsstack_copy_inode_size(file->f_path.dentry->d_inode, + file_inode(lower_file)); + fsstack_copy_attr_times(file->f_path.dentry->d_inode, + file_inode(lower_file)); + } out: return err; } From f9209e981afd8955a817582a4a9ba200c6b9bb15 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 24 Apr 2017 16:11:03 -0700 Subject: [PATCH 17/22] ANDROID: sdcardfs: Avoid setting GIDs outside of valid ranges When setting up the ownership of files on the lower filesystem, ensure that these values are in reasonable ranges for apps. If they aren't, default to AID_MEDIA_RW Signed-off-by: Daniel Rosenberg Bug: 37516160 Change-Id: I0bec76a61ac72aff0b993ab1ad04be8382178a00 --- fs/sdcardfs/derived_perm.c | 8 ++++---- fs/sdcardfs/multiuser.h | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 29645276c734..5a0ef3889846 100644 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -215,16 +215,16 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name) gid = AID_MEDIA_OBB; break; case PERM_ANDROID_PACKAGE: - if (info->d_uid != 0) + if (uid_is_app(info->d_uid)) gid = multiuser_get_ext_gid(info->d_uid); else - gid = multiuser_get_uid(info->userid, uid); + gid = multiuser_get_uid(info->userid, AID_MEDIA_RW); break; case PERM_ANDROID_PACKAGE_CACHE: - if (info->d_uid != 0) + if (uid_is_app(info->d_uid)) gid = multiuser_get_ext_cache_gid(info->d_uid); else - gid = multiuser_get_uid(info->userid, uid); + gid = multiuser_get_uid(info->userid, AID_MEDIA_RW); break; case PERM_PRE_ROOT: default: diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h index d0c925cda299..85341e753f8c 100644 --- a/fs/sdcardfs/multiuser.h +++ b/fs/sdcardfs/multiuser.h @@ -35,6 +35,13 @@ static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); } +static inline bool uid_is_app(uid_t uid) +{ + appid_t appid = uid % AID_USER_OFFSET; + + return appid >= AID_APP_START && appid <= AID_APP_END; +} + static inline gid_t multiuser_get_ext_cache_gid(uid_t uid) { return uid - AID_APP_START + AID_EXT_CACHE_GID_START; From 6bf837d910ccfe754de58c474e88bfe5ae454c3f Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 24 Apr 2017 19:49:02 -0700 Subject: [PATCH 18/22] ANDROID: sdcardfs: Call lower fs's revalidate We should be calling the lower filesystem's revalidate inside of sdcardfs's revalidate, as wrapfs does. Signed-off-by: Daniel Rosenberg Bug: 35766959 Change-Id: I939d1c4192fafc1e21678aeab43fe3d588b8e2f4 --- fs/sdcardfs/dentry.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index afd97710f7ad..ae2b4babe2e5 100644 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -60,6 +60,14 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) lower_dentry = lower_path.dentry; lower_cur_parent_dentry = dget_parent(lower_dentry); + if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) { + err = lower_dentry->d_op->d_revalidate(lower_dentry, flags); + if (err == 0) { + d_drop(dentry); + goto out; + } + } + spin_lock(&lower_dentry->d_lock); if (d_unhashed(lower_dentry)) { spin_unlock(&lower_dentry->d_lock); From 0df2f98282feee913dcb79f78c47c9139dc178f8 Mon Sep 17 00:00:00 2001 From: Daniel Roseberg Date: Tue, 9 May 2017 13:36:35 -0700 Subject: [PATCH 19/22] ANDROID: sdcardfs: Don't iput if we didn't igrab If we fail to get top, top is either NULL, or igrab found that we're in the process of freeing that inode, and did not grab it. Either way, we didn't grab it, and have no business putting it. Signed-off-by: Daniel Rosenberg Bug: 38117720 Change-Id: Ie2f587483b9abb5144263156a443e89bc69b767b --- fs/sdcardfs/inode.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 92afceb4fc65..4d558b87fe42 100644 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -622,11 +622,8 @@ static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int ma struct inode tmp; struct inode *top = grab_top(SDCARDFS_I(inode)); - if (!top) { - release_top(SDCARDFS_I(inode)); - WARN(1, "Top value was null!\n"); + if (!top) return -EINVAL; - } /* * Permission check on sdcardfs inode. @@ -701,10 +698,8 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct inode = d_inode(dentry); top = grab_top(SDCARDFS_I(inode)); - if (!top) { - release_top(SDCARDFS_I(inode)); + if (!top) return -EINVAL; - } /* * Permission check on sdcardfs inode. From 3e5807cff75e21f914a7652d14ffbb6561de2aa7 Mon Sep 17 00:00:00 2001 From: Steve Muckle Date: Tue, 9 May 2017 18:05:15 -0700 Subject: [PATCH 20/22] ANDROID: android-base.cfg: remove NETFILTER_XT_MATCH_QUOTA2_LOG There are currently a couple different implementations for this functionality. Until things are unified, remove the requirement for this kernel config. Bug: 37749708 Change-Id: I51cf883fd737412b0b9d3a1e570f92d9aa887f86 Signed-off-by: Steve Muckle --- kernel/configs/android-base.config | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index 3c32c74c584a..23686fc15d45 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -86,7 +86,6 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y From 13fb093578d3f0cf64b9416deae1568c1f1599f3 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Wed, 10 May 2017 23:01:15 +0800 Subject: [PATCH 21/22] ANDROID: sdcardfs: fix sdcardfs_destroy_inode for the inode RCU approach According to the following commits, fs: icache RCU free inodes vfs: fix the stupidity with i_dentry in inode destructors sdcardfs_destroy_inode should be fixed for the fast path safety. Signed-off-by: Gao Xiang Change-Id: I84f43c599209d23737c7e28b499dd121cb43636d --- fs/sdcardfs/super.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index a3393e959c63..8a9c9c7adca2 100644 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -192,9 +192,16 @@ static struct inode *sdcardfs_alloc_inode(struct super_block *sb) return &i->vfs_inode; } +static void i_callback(struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); + + kmem_cache_free(sdcardfs_inode_cachep, SDCARDFS_I(inode)); +} + static void sdcardfs_destroy_inode(struct inode *inode) { - kmem_cache_free(sdcardfs_inode_cachep, SDCARDFS_I(inode)); + call_rcu(&inode->i_rcu, i_callback); } /* sdcardfs inode cache constructor */ From f117eaf0a3193aef0e1eb66e08f5e224b61f1c6d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 10 May 2017 23:54:04 +0900 Subject: [PATCH 22/22] ANDROID: make PF_KEY SHA256 use RFC-compliant truncation. When using the PF_KEY interface, SHA-256 hashes are hardcoded to use 96-bit truncation. This is a violation of RFC4868, which specifies 128-bit truncation, but will not be fixed upstream due to backwards compatibility concerns and because the PF_KEY interface is deprecated in favour of netlink XFRM (which allows the app to specify an arbitrary truncation length). Change the hardcoded truncation length from 96 to 128 so that PF_KEY apps such as racoon will work with standards-compliant VPN servers. Bug: 34114242 Change-Id: Ie46bff4b6358f18117d0be241171d677d31d33f7 Signed-off-by: Lorenzo Colitti --- net/xfrm/xfrm_algo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 44ac85fe2bc9..d0ca0dbf494e 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -241,7 +241,7 @@ static struct xfrm_algo_desc aalg_list[] = { .uinfo = { .auth = { - .icv_truncbits = 96, + .icv_truncbits = 128, .icv_fullbits = 256, } },