[PATCH v4] udp reuseport: fix packet of same flow hashed to different socket
From: "Su, Xuemin" There is a corner case in which udp packets belonging to a same flow are hashed to different socket when hslot->count changes from 10 to 11: 1) When hslot->count <= 10, __udp_lib_lookup() searches udp_table->hash, and always passes 'daddr' to udp_ehashfn(). 2) When hslot->count > 10, __udp_lib_lookup() searches udp_table->hash2, but may pass 'INADDR_ANY' to udp_ehashfn() if the sockets are bound to INADDR_ANY instead of some specific addr. That means when hslot->count changes from 10 to 11, the hash calculated by udp_ehashfn() is also changed, and the udp packets belonging to a same flow will be hashed to different socket. This is easily reproduced: 1) Create 10 udp sockets and bind all of them to 0.0.0.0:4. 2) From the same host send udp packets to 127.0.0.1:4, record the socket index which receives the packets. 3) Create 1 more udp socket and bind it to 0.0.0.0:44096. The number 44096 is 4 + UDP_HASH_SIZE(4096), this makes the new socket put into the same hslot as the aformentioned 10 sockets, and makes the hslot->count change from 10 to 11. 4) From the same host send udp packets to 127.0.0.1:4, and the socket index which receives the packets will be different from the one received in step 2. This should not happen as the socket bound to 0.0.0.0:44096 should not change the behavior of the sockets bound to 0.0.0.0:4. It's the same case for IPv6, and this patch also fixes that. Signed-off-by: Su, Xuemin Signed-off-by: Eric Dumazet --- I use this tree to generate the patch: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git net/ipv4/udp.c | 73 +- net/ipv6/udp.c | 71 +--- 2 files changed, 32 insertions(+), 112 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0ff31d9..55ec77c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -391,9 +391,9 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum) return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr); } -static inline int compute_score(struct sock *sk, struct net *net, - __be32 saddr, unsigned short hnum, __be16 sport, - __be32 daddr, __be16 dport, int dif) +static int compute_score(struct sock *sk, struct net *net, +__be32 saddr, __be16 sport, +__be32 daddr, unsigned short hnum, int dif) { int score; struct inet_sock *inet; @@ -434,52 +434,6 @@ static inline int compute_score(struct sock *sk, struct net *net, return score; } -/* - * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num) - */ -static inline int compute_score2(struct sock *sk, struct net *net, -__be32 saddr, __be16 sport, -__be32 daddr, unsigned int hnum, int dif) -{ - int score; - struct inet_sock *inet; - - if (!net_eq(sock_net(sk), net) || - ipv6_only_sock(sk)) - return -1; - - inet = inet_sk(sk); - - if (inet->inet_rcv_saddr != daddr || - inet->inet_num != hnum) - return -1; - - score = (sk->sk_family == PF_INET) ? 2 : 1; - - if (inet->inet_daddr) { - if (inet->inet_daddr != saddr) - return -1; - score += 4; - } - - if (inet->inet_dport) { - if (inet->inet_dport != sport) - return -1; - score += 4; - } - - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - return -1; - score += 4; - } - - if (sk->sk_incoming_cpu == raw_smp_processor_id()) - score++; - - return score; -} - static u32 udp_ehashfn(const struct net *net, const __be32 laddr, const __u16 lport, const __be32 faddr, const __be16 fport) @@ -492,11 +446,11 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr, udp_ehash_secret + net_hash_mix(net)); } -/* called with read_rcu_lock() */ +/* called with rcu_read_lock() */ static struct sock *udp4_lib_lookup2(struct net *net, __be32 saddr, __be16 sport, __be32 daddr, unsigned int hnum, int dif, - struct udp_hslot *hslot2, unsigned int slot2, + struct udp_hslot *hslot2, struct sk_buff *skb) { struct sock *sk, *result; @@ -506,7 +460,7 @@ static struct sock *udp4_lib_lookup2(struct net *net, result = NULL; badness = 0; udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { - score = compute_score2(sk, net, saddr, sport, +
[PATCH v3] udp reuseport: fix packet of same flow hashed to different socket
From: "Su, Xuemin" There is a corner case in which udp packets belonging to a same flow are hashed to different socket when hslot->count changes from 10 to 11: 1) When hslot->count <= 10, __udp_lib_lookup() searches udp_table->hash, and always passes 'daddr' to udp_ehashfn(). 2) When hslot->count > 10, __udp_lib_lookup() searches udp_table->hash2, but may pass 'INADDR_ANY' to udp_ehashfn() if the sockets are bound to INADDR_ANY instead of some specific addr. That means when hslot->count changes from 10 to 11, the hash calculated by udp_ehashfn() is also changed, and the udp packets belonging to a same flow will be hashed to different socket. This is easily reproduced: 1) Create 10 udp sockets and bind all of them to 0.0.0.0:4. 2) From the same host send udp packets to 127.0.0.1:4, record the socket index which receives the packets. 3) Create 1 more udp socket and bind it to 0.0.0.0:44096. The number 44096 is 4 + UDP_HASH_SIZE(4096), this makes the new socket put into the same hslot as the aformentioned 10 sockets, and makes the hslot->count change from 10 to 11. 4) From the same host send udp packets to 127.0.0.1:4, and the socket index which receives the packets will be different from the one received in step 2. This should not happen as the socket bound to 0.0.0.0:44096 should not change the behavior of the sockets bound to 0.0.0.0:4. It's the same case for IPv6, and this patch also fixes that. Signed-off-by: Su, Xuemin Signed-off-by: Eric Dumazet --- I use this tree to generate the patch: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git net/ipv4/udp.c | 68 -- net/ipv6/udp.c | 66 2 files changed, 28 insertions(+), 106 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0ff31d9..586f1b0 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -391,9 +391,9 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum) return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr); } -static inline int compute_score(struct sock *sk, struct net *net, - __be32 saddr, unsigned short hnum, __be16 sport, - __be32 daddr, __be16 dport, int dif) +static int compute_score(struct sock *sk, struct net *net, +__be32 saddr, __be16 sport, +__be32 daddr, unsigned short hnum, int dif) { int score; struct inet_sock *inet; @@ -434,52 +434,6 @@ static inline int compute_score(struct sock *sk, struct net *net, return score; } -/* - * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num) - */ -static inline int compute_score2(struct sock *sk, struct net *net, -__be32 saddr, __be16 sport, -__be32 daddr, unsigned int hnum, int dif) -{ - int score; - struct inet_sock *inet; - - if (!net_eq(sock_net(sk), net) || - ipv6_only_sock(sk)) - return -1; - - inet = inet_sk(sk); - - if (inet->inet_rcv_saddr != daddr || - inet->inet_num != hnum) - return -1; - - score = (sk->sk_family == PF_INET) ? 2 : 1; - - if (inet->inet_daddr) { - if (inet->inet_daddr != saddr) - return -1; - score += 4; - } - - if (inet->inet_dport) { - if (inet->inet_dport != sport) - return -1; - score += 4; - } - - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - return -1; - score += 4; - } - - if (sk->sk_incoming_cpu == raw_smp_processor_id()) - score++; - - return score; -} - static u32 udp_ehashfn(const struct net *net, const __be32 laddr, const __u16 lport, const __be32 faddr, const __be16 fport) @@ -492,7 +446,7 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr, udp_ehash_secret + net_hash_mix(net)); } -/* called with read_rcu_lock() */ +/* called with rcu_read_lock() */ static struct sock *udp4_lib_lookup2(struct net *net, __be32 saddr, __be16 sport, __be32 daddr, unsigned int hnum, int dif, @@ -506,7 +460,7 @@ static struct sock *udp4_lib_lookup2(struct net *net, result = NULL; badness = 0; udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { - score = compute_score2(sk, net, saddr, sport, + score = compute_score(sk, net, saddr, sport, daddr, hnum, dif); if (score > badness) { reus
Re: [PATCH v2] udp reuseport: fix packet of same flow hashed to different socket
On Wed 2016-06-08 at 08:43 -0700, Eric Dumazet wrote: > I am not convinced this is the right way to fix the issue. > > Fact that you did not change udp4_lib_lookup2() is telling me something. > > > 1) If host has 100 different IP, and 10 sockets bound to 0.0.0.0:53 > 2) If we receive datagrams from SRCIP:srcport send to IP{1..100}:53 > will all be hashed on same slot. > > See the hash used in soreuseport logic as an equivalent of a 4-tuple > hash really, not a 3-tuple one. > This is my understanding of __udp4_lib_lookup(), see the comments below, please kindly review it. The problem of the current code is: In Path 1, we pass daddr to udp_ehashfn() inside udp4_lib_lookup2(). In Path 2, we pass 0.0.0.0 to udp_ehashfn() inside udp4_lib_lookup2(). In Path 3, we pass daddr to udp_ehashfn(), even if inet->inet_rcv_saddr is 0.0.0.0. The hash value returned by udp_ehashfn() is used as a random seed to select socket from the sockets of a hslot. In Path 2 and Path 3, this hash value is different, so we will select different sockets. Pass inet->inet_rcv_saddr to udp_ehashfn() in Path 3 will make the logic consistent in all these three Pathes. ... if (hslot->count > 10) { /* Xuemin: * for udptable->hash2[], sockets bound to specific ip and * sockets bound to 0.0.0.0 may be placed in different hslot, * so we may have to search two hslots. */ ... /* Xuemin Path 1: * for udptable->hash2[], firstly try to find the socket * bound to the specific daddr. */ result = udp4_lib_lookup2(net, saddr, sport, daddr, hnum, dif, hslot2, slot2, skb); if (!result) { /* Xuemin Path 2: * for udptable->hash2[], if we can not find the * socket bound to the specific daddr, we then * try to find the socket bound to 0.0.0.0. */ result = udp4_lib_lookup2(net, saddr, sport, htonl(INADDR_ANY), hnum, dif, hslot2, slot2, skb); } return result; } /* Xuemin: * for udptable->hash[], all sockets bound to the same * port(no matter they are bound to specific ip or to 0.0.0.0) * are placed in the same hslot, so we only need to search one * hslot. */ begin: result = NULL; badness = 0; sk_for_each_rcu(sk, &hslot->head) { score = compute_score(sk, net, saddr, hnum, sport, daddr, dport, dif); if (score > badness) { reuseport = sk->sk_reuseport; if (reuseport) { /* Xuemin Path 3: * when inet_sk(sk)->inet_rcv_saddr is 0.0.0.0, * we should not pass daddr here. */ hash = udp_ehashfn(net, daddr, hnum, saddr, sport); result = reuseport_select_sock(sk, hash, skb, sizeof(struct udphdr));
[PATCH v2] udp reuseport: fix packet of same flow hashed to different socket
From: "Su, Xuemin" There is a corner case in which udp packets belonging to a same flow are hashed to different socket when hslot->count changes from 10 to 11: 1) When hslot->count <= 10, __udp_lib_lookup() searches udp_table->hash, and always passes 'daddr' to udp_ehashfn(). 2) When hslot->count > 10, __udp_lib_lookup() searches udp_table->hash2, but may pass 'INADDR_ANY' to udp_ehashfn() if the sockets are bound to INADDR_ANY instead of some specific addr. That means when hslot->count changes from 10 to 11, the hash calculated by udp_ehashfn() is also changed, and the udp packets belonging to a same flow will be hashed to different socket. This is easily reproduced: 1) Create 10 udp sockets and bind all of them to 0.0.0.0:4. 2) From the same host send udp packets to 127.0.0.1:4, record the socket index which receives the packets. 3) Create 1 more udp socket and bind it to 0.0.0.0:44096. The number 44096 is 4 + UDP_HASH_SIZE(4096), this makes the new socket put into the same hslot as the aformentioned 10 sockets, and makes the hslot->count change from 10 to 11. 4) From the same host send udp packets to 127.0.0.1:4, and the socket index which receives the packets will be different from the one received in step 2. This should not happen as the socket bound to 0.0.0.0:44096 should not change the behavior of the sockets bound to 0.0.0.0:4. The fix here is that when searching udp_table->hash, if the socket supports reuseport, pass inet_sk(sk)->inet_rcv_saddr to udp_ehashfn() instead of daddr. When the sockets are bound to some specific addr, inet_sk(sk)->inet_rcv_saddr should equal to daddr, and when the sockets are bould to INADDR_ANY, this will pass INADDR_ANY to udp_ehashfn() as what is done when searching udp_table->hash2. It's the same case for IPv6, and this patch also fixes that. Signed-off-by: Su, Xuemin --- The patch v1 does not fix the code in IPv6. Thank Eric Dumazet for pointing that. And I use this tree to generate this patch, hope it's correct: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git net/ipv4/udp.c | 4 +++- net/ipv6/udp.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d56c055..57c38f6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -577,7 +577,9 @@ begin: if (score > badness) { reuseport = sk->sk_reuseport; if (reuseport) { - hash = udp_ehashfn(net, daddr, hnum, + hash = udp_ehashfn(net, + inet_sk(sk)->inet_rcv_saddr, + hnum, saddr, sport); result = reuseport_select_sock(sk, hash, skb, sizeof(struct udphdr)); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 2da1896..41ca493 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -290,7 +290,9 @@ begin: if (score > badness) { reuseport = sk->sk_reuseport; if (reuseport) { - hash = udp6_ehashfn(net, daddr, hnum, + hash = udp6_ehashfn(net, + &sk->sk_v6_rcv_saddr, + hnum, saddr, sport); result = reuseport_select_sock(sk, hash, skb, sizeof(struct udphdr)); -- 1.8.3.1
[PATCH] udp reuseport: fix packet of same flow hashed to different socket
From: "Su, Xuemin" There is a corner case in which udp packets belonging to a same flow are hashed to different socket when hslot->count changes from 10 to 11: 1) When hslot->count <= 10, __udp_lib_lookup() searches udp_table->hash, and always passes 'daddr' to udp_ehashfn(). 2) When hslot->count > 10, __udp_lib_lookup() searches udp_table->hash2, but may pass 'INADDR_ANY' to udp_ehashfn() if the sockets are bound to INADDR_ANY instead of some specific addr. That means when hslot->count changes from 10 to 11, the hash calculated by udp_ehashfn() is also changed, and the udp packets belonging to a same flow will be hashed to different socket. This is easily reproduced: 1) Create 10 udp sockets and bind all of them to 0.0.0.0:4. 2) From the same host send udp packets to 127.0.0.1:4, record the socket index which receives the packets. 3) Create 1 more udp socket and bind it to 0.0.0.0:44096. The number 44096 is 4 + UDP_HASH_SIZE(4096), this makes the new socket put into the same hslot as the aformentioned 10 sockets, and makes the hslot->count change from 10 to 11. 4) From the same host send udp packets to 127.0.0.1:4, and the socket index which receives the packets will be different from the one received in step 2. This should not happen as the socket bound to 0.0.0.0:44096 should not change the behavior of the sockets bound to 0.0.0.0:4. The fix here is that when searching udp_table->hash, if the socket supports reuseport, pass inet_sk(sk)->inet_rcv_saddr to udp_ehashfn() instead of daddr. When the sockets are bound to some specific addr, inet_sk(sk)->inet_rcv_saddr should equal to daddr, and when the sockets are bould to INADDR_ANY, this will pass INADDR_ANY to udp_ehashfn() as what is done when searching udp_table->hash2. Signed-off-by: Su, Xuemin --- net/ipv4/udp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d56c055..57c38f6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -577,7 +577,9 @@ begin: if (score > badness) { reuseport = sk->sk_reuseport; if (reuseport) { - hash = udp_ehashfn(net, daddr, hnum, + hash = udp_ehashfn(net, + inet_sk(sk)->inet_rcv_saddr, + hnum, saddr, sport); result = reuseport_select_sock(sk, hash, skb, sizeof(struct udphdr)); -- 1.8.3.1
[PATCH] drm/radeon: Calling object_unrefer() when creating fb failure
From: liu chuansheng Date: Thu, 31 Jan 2013 22:13:00 +0800 Subject: [PATCH] drm/radeon: Calling object_unrefer() when creating fb failure When kzalloc() failed in radeon_user_framebuffer_create(), need to call object_unreference() to match the object_reference(). Signed-off-by: liu chuansheng Signed-off-by: xueminsu --- drivers/gpu/drm/radeon/radeon_display.c |4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index ff3def7..05c96fa 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1115,8 +1115,10 @@ radeon_user_framebuffer_create(struct drm_device *dev, } radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); - if (radeon_fb == NULL) + if (radeon_fb == NULL) { + drm_gem_object_unreference_unlocked(obj); return ERR_PTR(-ENOMEM); + } ret = radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj); if (ret) { -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
RE: [PATCH V3] drm_crtc: check if fb_create return NULL
-Original Message- From: Jani Nikula [mailto:jani.nik...@linux.intel.com] Sent: Thursday, January 24, 2013 5:05 PM To: Su, Xuemin Cc: airl...@linux.ie; dri-de...@lists.freedesktop.org; linux-kernel@vger.kernel.org; yanmin_zh...@linux.intel.com; He, Bo Subject: Re: [PATCH V3] drm_crtc: check if fb_create return NULL >Ah, sorry, never mind, I missed Daniel's comment. The benefit of the >BUG_ON() is making it clear what's expected of the drivers. >Reviewed-by: Jani Nikula Do you think this patch is still needed? Currently I fix a buggy function radeon_user_framebuffer_create() which returns NULL and patch is added to 3.7-stable tree. Do you think it's also needed to do something in drm_mode_addfb()? Thanks. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V3] drm_crtc: check if fb_create return NULL
On Thu, 2013-01-24 at 10:31 +0200, Jani Nikula wrote: > > } > > + /* some buggy driver may return NULL here, which may cause panic */ > > + BUG_ON(!fb); > > I fail to see the benefit of this compared to just letting it oops... > > > or->fb_id = fb->base.id; > > ...right here. > > For PATCH V3, I think a BUG_ON may give the user clearer information about the reason of panic. Easier to debug. I submitted a PATCH V2 yesterday which gives a warning and then return -EVAL if fb==NULL, preventing the panic. Do you think this is acceptable? -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3] drm_crtc: check if fb_create return NULL
From: xueminsu Date: Tue, 22 Jan 2013 22:39:39 +0800 Subject: [PATCH] drm_crtc: check if fb_create return NULL Some buggy driver may still return NULL in fb_create, which leads to kernel panic. Signed-off-by: xueminsu --- drivers/gpu/drm/drm_crtc.c |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f2d667b..ae613ec 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2172,6 +2172,8 @@ int drm_mode_addfb(struct drm_device *dev, ret = PTR_ERR(fb); goto out; } + /* some buggy driver may return NULL here, which may cause panic */ + BUG_ON(!fb); or->fb_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
RE: [PATCH V2 RESEND] drm_crtc: check if fb_create return NULL
-Original Message- >From: Daniel Vetter [mailto:daniel.vet...@ffwll.ch] On Behalf Of Daniel Vetter >Sent: Wednesday, January 23, 2013 5:54 PM >To: Su, Xuemin >Cc: airl...@linux.ie; dri-de...@lists.freedesktop.org; >linux-kernel@vger.kernel.org; yanmin_zh...@linux.intel.com; He, Bo >Subject: Re: [PATCH V2 RESEND] drm_crtc: check if fb_create return NULL >Imo just BUG_ON(!fb); and call it a day. Makes it pretty clear what's expected >of the drivers. >-Daniel Thanks, I will upload PATCH V3. Xuemin -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 RESEND] drm_crtc: check if fb_create return NULL
From: xueminsu Date: Tue, 22 Jan 2013 22:39:39 +0800 Subject: [PATCH] drm_crtc: check if fb_create return NULL Some buggy driver may still return NULL in fb_create, which leads to kernel panic. Signed-off-by: xueminsu --- drivers/gpu/drm/drm_crtc.c |7 +++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f2d667b..b748498 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2172,6 +2172,13 @@ int drm_mode_addfb(struct drm_device *dev, ret = PTR_ERR(fb); goto out; } + /* some buggy driver may return NULL here, which may cause panic */ + if (!fb) { + WARN(1, "%pf should not return NULL.", + dev->mode_config.funcs->fb_create); + ret = -EINVAL; + goto out; + } or->fb_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] drm_crtc: check if fb_create return NULL
From: xueminsu Date: Tue, 22 Jan 2013 22:39:39 +0800 Subject: [PATCH] drm_crtc: check if fb_create return NULL Some buggy driver may still return NULL in fb_create, which leads to kernel panic. Signed-off-by: xueminsu --- drivers/gpu/drm/drm_crtc.c |6 ++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f2d667b..4ed0aed 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2172,6 +2172,12 @@ int drm_mode_addfb(struct drm_device *dev, ret = PTR_ERR(fb); goto out; } + /* some buggy driver may return NULL here, which may cause panic */ + if (!fb) { + WARN(1, "%pf should not return NULL.", + dev->mode_config.funcs->fb_create); + return -EINVAL; + } or->fb_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] radeon_display: Use pointer return error codes
From: xueminsu Date: Tue, 22 Jan 2013 22:16:53 +0800 Subject: [PATCH] radeon_display: Use pointer return error codes drm_mode_addfb() expects fb_create return error code instead of NULL. Signed-off-by: xueminsu --- drivers/gpu/drm/radeon/radeon_display.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1da2386..ff3def7 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1122,7 +1122,7 @@ radeon_user_framebuffer_create(struct drm_device *dev, if (ret) { kfree(radeon_fb); drm_gem_object_unreference_unlocked(obj); - return NULL; + return ERR_PTR(ret); } return &radeon_fb->base; -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/