Re: [PATCH net] sctp: frag_point sanity check
Hi Jakub, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on net/master] url: https://github.com/0day-ci/linux/commits/Jakub-Audykowicz/sctp-frag_point-sanity-check/20181206-011917 config: x86_64-randconfig-x015-12051035 (attached as .config) compiler: gcc-7 (Debian 7.3.0-1) 7.3.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 All warnings (new ones prefixed by >>): In file included from include/linux/kernel.h:14:0, from net/sctp/chunk.c:36: net/sctp/chunk.c: In function 'sctp_datamsg_from_user': include/linux/kern_levels.h:5:18: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t {aka long unsigned int}' [-Wformat=] #define KERN_SOH "\001" /* ASCII Start Of Header */ ^ include/linux/printk.h:429:10: note: in definition of macro 'printk_ratelimited' printk(fmt, ##__VA_ARGS__);\ ^~~ include/linux/kern_levels.h:12:22: note: in expansion of macro 'KERN_SOH' #define KERN_WARNING KERN_SOH "4" /* warning conditions */ ^~~~ include/linux/printk.h:445:21: note: in expansion of macro 'KERN_WARNING' printk_ratelimited(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) ^~~~ >> net/sctp/chunk.c:197:3: note: in expansion of macro 'pr_warn_ratelimited' pr_warn_ratelimited("%s: asoc:%p frag_point is zero, forcing max_data to default minimum (%d)", ^~~ vim +/pr_warn_ratelimited +197 net/sctp/chunk.c 156 157 158 /* A data chunk can have a maximum payload of (2^16 - 20). Break 159 * down any such message into smaller chunks. Opportunistically, fragment 160 * the chunks down to the current MTU constraints. We may get refragmented 161 * later if the PMTU changes, but it is _much better_ to fragment immediately 162 * with a reasonable guess than always doing our fragmentation on the 163 * soft-interrupt. 164 */ 165 struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, 166 struct sctp_sndrcvinfo *sinfo, 167 struct iov_iter *from) 168 { 169 size_t len, first_len, max_data, remaining; 170 size_t msg_len = iov_iter_count(from); 171 struct sctp_shared_key *shkey = NULL; 172 struct list_head *pos, *temp; 173 struct sctp_chunk *chunk; 174 struct sctp_datamsg *msg; 175 int err; 176 177 msg = sctp_datamsg_new(GFP_KERNEL); 178 if (!msg) 179 return ERR_PTR(-ENOMEM); 180 181 /* Note: Calculate this outside of the loop, so that all fragments 182 * have the same expiration. 183 */ 184 if (asoc->peer.prsctp_capable && sinfo->sinfo_timetolive && 185 (SCTP_PR_TTL_ENABLED(sinfo->sinfo_flags) || 186 !SCTP_PR_POLICY(sinfo->sinfo_flags))) 187 msg->expires_at = jiffies + 188 msecs_to_jiffies(sinfo->sinfo_timetolive); 189 190 /* This is the biggest possible DATA chunk that can fit into 191 * the packet 192 */ 193 max_data = asoc->frag_point; 194 if (unlikely(!max_data)) { 195 max_data = sctp_min_frag_point(sctp_sk(asoc->base.sk), 196 sctp_datachk_len(>stream)); > 197 pr_warn_ratelimited("%s: asoc:%p frag_point is zero, > forcing max_data to default minimum (%d)", 198 __func__, asoc, max_data); 199 } 200 201 /* If the the peer requested that we authenticate DATA chunks 202 * we need to account for bundling of the AUTH chunks along with 203 * DATA. 204 */ 205 if (sctp_auth_send_cid(SCTP_CID_DATA, asoc)) { 206 struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc); 207 208 if (hmac_desc) 209 max_data -= SCTP_PAD4(sizeof(struct sctp_auth_chunk) + 210hmac_desc->hmac_len); 211 212 if (sinfo->sinfo_tsn && 213 sinfo->sinfo_ssn != asoc->active_key_id) { 214 shkey = sctp_auth_get_shkey(asoc, sinfo->sinfo_ssn); 215 if (!shkey) { 216 err = -EINVAL; 217 goto errout; 218 } 219 } else { 220 shkey = asoc->shkey; 221 } 222 } 223
Re: [PATCH net] sctp: frag_point sanity check
From: Jakub Audykowicz Date: Tue, 4 Dec 2018 20:27:41 +0100 > If for some reason an association's fragmentation point is zero, > sctp_datamsg_from_user will try to endlessly try to divide a message > into zero-sized chunks. This eventually causes kernel panic due to > running out of memory. > > Although this situation is quite unlikely, it has occurred before as > reported. I propose to add this simple last-ditch sanity check due to > the severity of the potential consequences. > > Signed-off-by: Jakub Audykowicz Applied.
Re: [PATCH net] sctp: frag_point sanity check
On Tue, Dec 04, 2018 at 03:56:33PM -0500, Neil Horman wrote: > On Tue, Dec 04, 2018 at 05:52:02PM -0200, Marcelo Ricardo Leitner wrote: > > On Tue, Dec 04, 2018 at 02:39:46PM -0500, Neil Horman wrote: > > > On Tue, Dec 04, 2018 at 08:27:41PM +0100, Jakub Audykowicz wrote: > > > > If for some reason an association's fragmentation point is zero, > > > > sctp_datamsg_from_user will try to endlessly try to divide a message > > > > into zero-sized chunks. This eventually causes kernel panic due to > > > > running out of memory. > > > > > > > > Although this situation is quite unlikely, it has occurred before as > > > > reported. I propose to add this simple last-ditch sanity check due to > > > > the severity of the potential consequences. > > > > > > > > Signed-off-by: Jakub Audykowicz > > > > --- > > > > include/net/sctp/sctp.h | 5 + > > > > net/sctp/chunk.c| 6 ++ > > > > net/sctp/socket.c | 3 +-- > > > > 3 files changed, 12 insertions(+), 2 deletions(-) > > > > > > > > diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h > > > > index ab9242e51d9e..2abbc15824af 100644 > > > > --- a/include/net/sctp/sctp.h > > > > +++ b/include/net/sctp/sctp.h > > > > @@ -620,4 +620,9 @@ static inline bool sctp_transport_pmtu_check(struct > > > > sctp_transport *t) > > > > return false; > > > > } > > > > > > > > +static inline __u32 sctp_min_frag_point(struct sctp_sock *sp, __u16 > > > > datasize) > > > > +{ > > > > + return sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, datasize); > > > > +} > > > > + > > > > #endif /* __net_sctp_h__ */ > > > > diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c > > > > index ce8087846f05..d5b91bc8a377 100644 > > > > --- a/net/sctp/chunk.c > > > > +++ b/net/sctp/chunk.c > > > > @@ -191,6 +191,12 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct > > > > sctp_association *asoc, > > > > * the packet > > > > */ > > > > max_data = asoc->frag_point; > > > > + if (unlikely(!max_data)) { > > > > + max_data = sctp_min_frag_point(sctp_sk(asoc->base.sk), > > > > + > > > > sctp_datachk_len(>stream)); > > > > + pr_warn_ratelimited("%s: asoc:%p frag_point is zero, > > > > forcing max_data to default minimum (%d)", > > > > + __func__, asoc, max_data); > > > > + } > > > > > > > > /* If the the peer requested that we authenticate DATA chunks > > > > * we need to account for bundling of the AUTH chunks along with > > > > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > > > > index bf618d1b41fd..b8cebd5a87e5 100644 > > > > --- a/net/sctp/socket.c > > > > +++ b/net/sctp/socket.c > > > > @@ -3324,8 +3324,7 @@ static int sctp_setsockopt_maxseg(struct sock > > > > *sk, char __user *optval, unsigned > > > > __u16 datasize = asoc ? sctp_datachk_len(>stream) > > > > : > > > > sizeof(struct sctp_data_chunk); > > > > > > > > - min_len = sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, > > > > - datasize); > > > > + min_len = sctp_min_frag_point(sp, datasize); > > > > max_len = SCTP_MAX_CHUNK_LEN - datasize; > > > > > > > > if (val < min_len || val > max_len) > > > > -- > > > > 2.17.1 > > > > > > > > > > > Why not just prevent the frag point from ever going below > > > SCTP_DEFAULT_MINSEGMENT in the first place in > > > sctp_assoc_update_frag_point? > > > Something like: > > > > > > asoc->frag_point = SCTP_TRUNC4(frag) < SCTP_DEFAILT_MINSEGMENT) ? \ > > > SCTP_DEFAILT_MINSEGMENT : SCTP_TRUNC4(frag); > > > > > > Should do the trick I would think > > > Neil > > > > This is in the light of "sctp: update frag_point when > > stream_interleave is set". > > > > Because of > > https://www.mail-archive.com/netdev@vger.kernel.org/msg256575.html > > This wouldn't have helped because sctp_assoc_update_frag_point() > > didn't get called. The issue is not that the calc issued a bad value, > > but that it wasn't done. > > > > Marcelo > > > Ah, thank you for the clarification. > > Acked-by: Neil Horman > Cool! Acked-by: Marcelo Ricardo Leitner
Re: [PATCH net] sctp: frag_point sanity check
On Tue, Dec 04, 2018 at 05:52:02PM -0200, Marcelo Ricardo Leitner wrote: > On Tue, Dec 04, 2018 at 02:39:46PM -0500, Neil Horman wrote: > > On Tue, Dec 04, 2018 at 08:27:41PM +0100, Jakub Audykowicz wrote: > > > If for some reason an association's fragmentation point is zero, > > > sctp_datamsg_from_user will try to endlessly try to divide a message > > > into zero-sized chunks. This eventually causes kernel panic due to > > > running out of memory. > > > > > > Although this situation is quite unlikely, it has occurred before as > > > reported. I propose to add this simple last-ditch sanity check due to > > > the severity of the potential consequences. > > > > > > Signed-off-by: Jakub Audykowicz > > > --- > > > include/net/sctp/sctp.h | 5 + > > > net/sctp/chunk.c| 6 ++ > > > net/sctp/socket.c | 3 +-- > > > 3 files changed, 12 insertions(+), 2 deletions(-) > > > > > > diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h > > > index ab9242e51d9e..2abbc15824af 100644 > > > --- a/include/net/sctp/sctp.h > > > +++ b/include/net/sctp/sctp.h > > > @@ -620,4 +620,9 @@ static inline bool sctp_transport_pmtu_check(struct > > > sctp_transport *t) > > > return false; > > > } > > > > > > +static inline __u32 sctp_min_frag_point(struct sctp_sock *sp, __u16 > > > datasize) > > > +{ > > > + return sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, datasize); > > > +} > > > + > > > #endif /* __net_sctp_h__ */ > > > diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c > > > index ce8087846f05..d5b91bc8a377 100644 > > > --- a/net/sctp/chunk.c > > > +++ b/net/sctp/chunk.c > > > @@ -191,6 +191,12 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct > > > sctp_association *asoc, > > >* the packet > > >*/ > > > max_data = asoc->frag_point; > > > + if (unlikely(!max_data)) { > > > + max_data = sctp_min_frag_point(sctp_sk(asoc->base.sk), > > > +sctp_datachk_len(>stream)); > > > + pr_warn_ratelimited("%s: asoc:%p frag_point is zero, forcing > > > max_data to default minimum (%d)", > > > + __func__, asoc, max_data); > > > + } > > > > > > /* If the the peer requested that we authenticate DATA chunks > > >* we need to account for bundling of the AUTH chunks along with > > > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > > > index bf618d1b41fd..b8cebd5a87e5 100644 > > > --- a/net/sctp/socket.c > > > +++ b/net/sctp/socket.c > > > @@ -3324,8 +3324,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, > > > char __user *optval, unsigned > > > __u16 datasize = asoc ? sctp_datachk_len(>stream) : > > >sizeof(struct sctp_data_chunk); > > > > > > - min_len = sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, > > > -datasize); > > > + min_len = sctp_min_frag_point(sp, datasize); > > > max_len = SCTP_MAX_CHUNK_LEN - datasize; > > > > > > if (val < min_len || val > max_len) > > > -- > > > 2.17.1 > > > > > > > > Why not just prevent the frag point from ever going below > > SCTP_DEFAULT_MINSEGMENT in the first place in sctp_assoc_update_frag_point? > > Something like: > > > > asoc->frag_point = SCTP_TRUNC4(frag) < SCTP_DEFAILT_MINSEGMENT) ? \ > > SCTP_DEFAILT_MINSEGMENT : SCTP_TRUNC4(frag); > > > > Should do the trick I would think > > Neil > > This is in the light of "sctp: update frag_point when > stream_interleave is set". > > Because of > https://www.mail-archive.com/netdev@vger.kernel.org/msg256575.html > This wouldn't have helped because sctp_assoc_update_frag_point() > didn't get called. The issue is not that the calc issued a bad value, > but that it wasn't done. > > Marcelo > Ah, thank you for the clarification. Acked-by: Neil Horman
Re: [PATCH net] sctp: frag_point sanity check
On Tue, Dec 04, 2018 at 02:39:46PM -0500, Neil Horman wrote: > On Tue, Dec 04, 2018 at 08:27:41PM +0100, Jakub Audykowicz wrote: > > If for some reason an association's fragmentation point is zero, > > sctp_datamsg_from_user will try to endlessly try to divide a message > > into zero-sized chunks. This eventually causes kernel panic due to > > running out of memory. > > > > Although this situation is quite unlikely, it has occurred before as > > reported. I propose to add this simple last-ditch sanity check due to > > the severity of the potential consequences. > > > > Signed-off-by: Jakub Audykowicz > > --- > > include/net/sctp/sctp.h | 5 + > > net/sctp/chunk.c| 6 ++ > > net/sctp/socket.c | 3 +-- > > 3 files changed, 12 insertions(+), 2 deletions(-) > > > > diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h > > index ab9242e51d9e..2abbc15824af 100644 > > --- a/include/net/sctp/sctp.h > > +++ b/include/net/sctp/sctp.h > > @@ -620,4 +620,9 @@ static inline bool sctp_transport_pmtu_check(struct > > sctp_transport *t) > > return false; > > } > > > > +static inline __u32 sctp_min_frag_point(struct sctp_sock *sp, __u16 > > datasize) > > +{ > > + return sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, datasize); > > +} > > + > > #endif /* __net_sctp_h__ */ > > diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c > > index ce8087846f05..d5b91bc8a377 100644 > > --- a/net/sctp/chunk.c > > +++ b/net/sctp/chunk.c > > @@ -191,6 +191,12 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct > > sctp_association *asoc, > > * the packet > > */ > > max_data = asoc->frag_point; > > + if (unlikely(!max_data)) { > > + max_data = sctp_min_frag_point(sctp_sk(asoc->base.sk), > > + sctp_datachk_len(>stream)); > > + pr_warn_ratelimited("%s: asoc:%p frag_point is zero, forcing > > max_data to default minimum (%d)", > > + __func__, asoc, max_data); > > + } > > > > /* If the the peer requested that we authenticate DATA chunks > > * we need to account for bundling of the AUTH chunks along with > > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > > index bf618d1b41fd..b8cebd5a87e5 100644 > > --- a/net/sctp/socket.c > > +++ b/net/sctp/socket.c > > @@ -3324,8 +3324,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, > > char __user *optval, unsigned > > __u16 datasize = asoc ? sctp_datachk_len(>stream) : > > sizeof(struct sctp_data_chunk); > > > > - min_len = sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, > > - datasize); > > + min_len = sctp_min_frag_point(sp, datasize); > > max_len = SCTP_MAX_CHUNK_LEN - datasize; > > > > if (val < min_len || val > max_len) > > -- > > 2.17.1 > > > > > Why not just prevent the frag point from ever going below > SCTP_DEFAULT_MINSEGMENT in the first place in sctp_assoc_update_frag_point? > Something like: > > asoc->frag_point = SCTP_TRUNC4(frag) < SCTP_DEFAILT_MINSEGMENT) ? \ > SCTP_DEFAILT_MINSEGMENT : SCTP_TRUNC4(frag); > > Should do the trick I would think > Neil This is in the light of "sctp: update frag_point when stream_interleave is set". Because of https://www.mail-archive.com/netdev@vger.kernel.org/msg256575.html This wouldn't have helped because sctp_assoc_update_frag_point() didn't get called. The issue is not that the calc issued a bad value, but that it wasn't done. Marcelo
Re: [PATCH net] sctp: frag_point sanity check
On Tue, Dec 04, 2018 at 08:27:41PM +0100, Jakub Audykowicz wrote: > If for some reason an association's fragmentation point is zero, > sctp_datamsg_from_user will try to endlessly try to divide a message > into zero-sized chunks. This eventually causes kernel panic due to > running out of memory. > > Although this situation is quite unlikely, it has occurred before as > reported. I propose to add this simple last-ditch sanity check due to > the severity of the potential consequences. > > Signed-off-by: Jakub Audykowicz > --- > include/net/sctp/sctp.h | 5 + > net/sctp/chunk.c| 6 ++ > net/sctp/socket.c | 3 +-- > 3 files changed, 12 insertions(+), 2 deletions(-) > > diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h > index ab9242e51d9e..2abbc15824af 100644 > --- a/include/net/sctp/sctp.h > +++ b/include/net/sctp/sctp.h > @@ -620,4 +620,9 @@ static inline bool sctp_transport_pmtu_check(struct > sctp_transport *t) > return false; > } > > +static inline __u32 sctp_min_frag_point(struct sctp_sock *sp, __u16 datasize) > +{ > + return sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, datasize); > +} > + > #endif /* __net_sctp_h__ */ > diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c > index ce8087846f05..d5b91bc8a377 100644 > --- a/net/sctp/chunk.c > +++ b/net/sctp/chunk.c > @@ -191,6 +191,12 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct > sctp_association *asoc, >* the packet >*/ > max_data = asoc->frag_point; > + if (unlikely(!max_data)) { > + max_data = sctp_min_frag_point(sctp_sk(asoc->base.sk), > +sctp_datachk_len(>stream)); > + pr_warn_ratelimited("%s: asoc:%p frag_point is zero, forcing > max_data to default minimum (%d)", > + __func__, asoc, max_data); > + } > > /* If the the peer requested that we authenticate DATA chunks >* we need to account for bundling of the AUTH chunks along with > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > index bf618d1b41fd..b8cebd5a87e5 100644 > --- a/net/sctp/socket.c > +++ b/net/sctp/socket.c > @@ -3324,8 +3324,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char > __user *optval, unsigned > __u16 datasize = asoc ? sctp_datachk_len(>stream) : >sizeof(struct sctp_data_chunk); > > - min_len = sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, > -datasize); > + min_len = sctp_min_frag_point(sp, datasize); > max_len = SCTP_MAX_CHUNK_LEN - datasize; > > if (val < min_len || val > max_len) > -- > 2.17.1 > > Why not just prevent the frag point from ever going below SCTP_DEFAULT_MINSEGMENT in the first place in sctp_assoc_update_frag_point? Something like: asoc->frag_point = SCTP_TRUNC4(frag) < SCTP_DEFAILT_MINSEGMENT) ? \ SCTP_DEFAILT_MINSEGMENT : SCTP_TRUNC4(frag); Should do the trick I would think Neil
[PATCH net] sctp: frag_point sanity check
If for some reason an association's fragmentation point is zero, sctp_datamsg_from_user will try to endlessly try to divide a message into zero-sized chunks. This eventually causes kernel panic due to running out of memory. Although this situation is quite unlikely, it has occurred before as reported. I propose to add this simple last-ditch sanity check due to the severity of the potential consequences. Signed-off-by: Jakub Audykowicz --- include/net/sctp/sctp.h | 5 + net/sctp/chunk.c| 6 ++ net/sctp/socket.c | 3 +-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index ab9242e51d9e..2abbc15824af 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -620,4 +620,9 @@ static inline bool sctp_transport_pmtu_check(struct sctp_transport *t) return false; } +static inline __u32 sctp_min_frag_point(struct sctp_sock *sp, __u16 datasize) +{ + return sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, datasize); +} + #endif /* __net_sctp_h__ */ diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index ce8087846f05..d5b91bc8a377 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -191,6 +191,12 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, * the packet */ max_data = asoc->frag_point; + if (unlikely(!max_data)) { + max_data = sctp_min_frag_point(sctp_sk(asoc->base.sk), + sctp_datachk_len(>stream)); + pr_warn_ratelimited("%s: asoc:%p frag_point is zero, forcing max_data to default minimum (%d)", + __func__, asoc, max_data); + } /* If the the peer requested that we authenticate DATA chunks * we need to account for bundling of the AUTH chunks along with diff --git a/net/sctp/socket.c b/net/sctp/socket.c index bf618d1b41fd..b8cebd5a87e5 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3324,8 +3324,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned __u16 datasize = asoc ? sctp_datachk_len(>stream) : sizeof(struct sctp_data_chunk); - min_len = sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, - datasize); + min_len = sctp_min_frag_point(sp, datasize); max_len = SCTP_MAX_CHUNK_LEN - datasize; if (val < min_len || val > max_len) -- 2.17.1